ksh script syntax error on date - unix

My shell script fails on this portion
dt=$(date +%Y%m%d)
syntax error at line 35: `dt=$' unexpected
It's a bit strange as I'm using the same to get the datetime and don't get any problem
timestamp=$(date +%Y%m%d%H%M%S)
20170911105251
I've checked in Notepad++ as well that I don't have any dirty characters as suggested by #Frank below
Below is the sample script I have. Please note I have omitted some portions that are confidential. Basically the script transfers files from Server A to B based on the dt specified. If no date parameter is specified during execution, it takes the current date.
if [ -z "$1" ]
then
dt=$(date +%Y%m%d)
else
dt=$1
fi
export rundate
timestamp=$(date +%Y%m%d%H%M%S)
logfile=${log_path}/${batch}-${dt}-${timestamp}.log
mail_file=${log_path}/${batch}-mail-${timestamp}.txt
export mail_file
filecount=$(wc -l ${batch_filelist} | cut -d " " -f 1)
sftp ${dest} <<EOF >> $logfile
cd $destdir
lcd $sourcedir
put -p *.txt
exit
EOF
mail -s "SFTP Done (dt:$dt)" $(cat $email_accounts) < $mail_file

Becarful , when you copy text from anywhere and paste in file (i think you did it) , it can add "dirty" characters .
If you have a text editor like notepad++ , by clicking on :
It will show all characters .
Via notepad++ you can change the file format from windows to unix , by right click on bottom-right in page :
Save the file and send again in to your machine .
The syntax seems correct so it should work .
Anyway i mentioned notepad++ but you can do this with other text editors.
dt=$(date +'%Y%m%d') and not dt=$(dt +'%Y%m%d')
A working example below :
!/usr/bin/bash
if [ -z $1 ]
then
dt=$(date +'%Y%m%d')
else
dt=$1
fi
echo $dt
Result :
xxxxxxxxxxxxxx:/pathtosh> prova.sh
20170911
xxxxxxxxxxxxxx:/pathtosh> prova.sh 1
1

Related

convert the CR/LF line terminators in that file to Unix-style LF line terminators?

Please help. I need to turn this in before 4pm for this Unix class. I have been working on it since 7pm last night. Haven't slept. There are three parts to this assignment. I only need help with the last part. If I can't complete this I fail the class.
Stage 3
In that same directory, write a script asciiFix.sh that takes an arbitrary number of file paths from the command line and carries out the same analysis on each one. If a file is not Windows ASCII, your script should do nothing to it. For each file that is Windows ASCII, your script should print the message
converting fileName
and should then convert the CR/LF line terminators in that file to Unix-style LF line terminators.
For example:
cp ~cs252/Assignments/ftpAsst/d3.dat wintest.txt
./asciiFix.sh /usr/share/dict/words wintest.txt fileType.sh
converting wintest.txt
and, after the script has finished, you should be able to determine that wintest.txt is now a Unix ASCII file.
When you believe that you have your script working, run
~cs252/bin/scriptAsst.pl
If all three scripts are working correctly, you will receive your access code.
My Attemps:
#!/bin/sh
for file in "$#" do
if file "$file" | grep "ASCII text, with CRLF"; then
echo "converting $file"
sed -e s/[\\r\\n]//g "$file"
fi
done
result:
./asciiFix.sh: 3: ./asciiFix.sh: Syntax error: "if" unexpected (expecting "do")
aardvark.cpp /home/cs252/Assignments/scriptAsst/winscrubbed.dat differ: byte 50, line 1
Failed: incorrect file conversion when running ./asciiFix.sh 'aardvark.cpp' 'bongo.dat' ' cat.dog.bak
Ii have tried taking out if and then. i have tried sed -i 's/^M//g' "$file",also using dos2unix, as well as some other stuff I dont remember. but it always says incorrect conversion with those files.
After adding the ; and switching to dos2unix:
#!/bin/sh
for file in "$#";
do
if file "$file" | grep "ASCII text, with CRLF"; then
echo "converting $file"
dos2unix "$file"
fi
done
the Error that I now get:
dos2unix: converting file aardvark.cpp to Unix format ...
Failed when running: ./asciiFix.sh 'aardvark.cpp' 'bongo.dat' 'cat.dog.bak'
Thanks for all your help.
The code that finally worked was:
#!/bin/sh
for file in "$#";
do
if file "$file" | grep -q "ASCII text, with CRLF"; then
echo "converting $file"
dos2unix "$file"
fi
done
You forgot the ; before do. do counts as a new statement. Alternatively you could place the do on a new line. In my opinion, the most comfortable way to convert DOS line endings (CRLF) to Unix line endings (LF-only) is dos2unix. If you fix your ;error, using dos2unix instead of sed should be straight forward and trivial.
Since dos2unix 7.1 you can use dos2unix itself to test for CRLF. This way you are not limited to ASCII.
#!/bin/sh
for file in "$#";
do
if [ -n "$(dos2unix -ic $file)" ]; then
echo "converting $file"
dos2unix "$file"
fi
done

Unix command to capitalize first letter of file name

I have a folder "activity" which contains files like getEmployee.java, getTable.java etc. I was wondering if there was a unix command that could replace the file Name to give me: GetEmployee.java, GetTable.java and so on.
I've tried mv getEmployee.java GetEmployee.java
However this is pretty cumbersome as you can imagine since i have almost 70 files. Is there a way in Unix I can do this? I usually use sed to replace stuff, but I don't think that works for filenames. Can someone please suggest an easier way please?
This is a shell script that will find *.java files in the local directory and alter them:
#!/bin/sh
find . -name "*.java" -print | gawk -F "/" '
{
new = sprintf( "%s%s", toupper( substr( $NF, 1, 1 ) ), substr( $NF, 2 ) )
cmd = sprintf( "mv %s %s", $NF, new )
# comment out the next two lines and uncomment the printf() to see the commands
cmd | getline ret_val
close( cmd )
#printf( "%s => ret_val = %s\n", cmd, ret_val"" )
} '
I saved it to a script named "alterjava", "chmod +x alterjava" then ran it on a directory of zero sized files I made up for testing. You can check the commands before running it by commenting out the cmd line and uncommenting the printf() line
Bash can perform case-replacement in parameter substitution, using ${^} to capitalise the first character:
#!/bin/bash
for i in *.java; do mv -v "$i" "${i^}"; done
Note that this is not standard POSIX; other shells need not have this feature
rename -vn 's/([a-z])(\w+.java)/\u$1$2/' *.java
remove -n to execute command

How to read 1 symbol in zsh?

I need to get exactly one character from console and not print it.
I've tried to use read -en 1 as I did using bash. But this doesn't work at all.
And vared doesn't seem to have such option.
How to read 1 symbol in zsh? (I'm using zsh v.4.3.11 and v.5.0.2)
read -sk
From the documentation:
-s
Don’t echo back characters if reading from the terminal. Currently does not work with the -q option.
-k [ num ]
Read only one (or num) characters. All are assigned to the first name, without word splitting. This flag is ignored when -q is present. Input is read from the terminal unless one of -u or -p is present. This option may also be used within zle widgets.
Note that despite the mnemonic ‘key’ this option does read full characters, which may consist of multiple bytes if the option MULTIBYTE is set.
If you want your script to be a bit more portable you can do something like this:
y=$(bash -c "read -n 1 c; echo \$c")
read reads from the terminal by default:
% date | read -sk1 "?Enter one char: "; echo $REPLY
Enter one char: X
Note above:
The output of date is discarded
The X is printed by the echo, not when the user enters it.
To read from a pipeline, use file descriptor 0:
% echo foobar | read -rk1 -u0; echo $REPLY
f
% echo $ZSH_VERSION
5.5.1
Try something like
read line
c=`echo $line | cut -c1`
echo $c

Unix command to prepend text to a file

Is there a Unix command to prepend some string data to a text file?
Something like:
prepend "to be prepended" text.txt
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
sed -i.old '1s;^;to be prepended;' inFile
-i writes the change in place and take a backup if any extension is given. (In this case, .old)
1s;^;to be prepended; substitutes the beginning of the first line by the given replacement string, using ; as a command delimiter.
Process Substitution
I'm surprised no one mentioned this.
cat <(echo "before") text.txt > newfile.txt
which is arguably more natural than the accepted answer (printing something and piping it into a substitution command is lexicographically counter-intuitive).
...and hijacking what ryan said above, with sponge you don't need a temporary file:
sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt
EDIT: Looks like this doesn't work in Bourne Shell /bin/sh
Here String (zsh only)
Using a here-string - <<<, you can do:
<<< "to be prepended" < text.txt | sponge text.txt
This is one possibility:
(echo "to be prepended"; cat text.txt) > newfile.txt
you'll probably not easily get around an intermediate file.
Alternatives (can be cumbersome with shell escaping):
sed -i '0,/^/s//to be prepended/' text.txt
If it's acceptable to replace the input file:
Note:
Doing so may have unexpected side effects, notably potentially replacing a symlink with a regular file, ending up with different permissions on the file, and changing the file's creation (birth) date.
sed -i, as in Prince John Wesley's answer, tries to at least restore the original permissions, but the other limitations apply as well.
Here's a simple alternative that uses a temporary file (it avoids reading the whole input file into memory the way that shime's solution does):
{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt
Using a group command ({ ...; ...; }) is slightly more efficient than using a subshell ((...; ...)), as in 0xC0000022L's solution.
The advantages are:
It's easy to control whether the new text should be directly prepended to the first line or whether it should be inserted as new line(s) (simply append \n to the printf argument).
Unlike the sed solution, it works if the input file is empty (0 bytes).
The sed solution can be simplified if the intent is to prepend one or more whole lines to the existing content (assuming the input file is non-empty):
sed's i function inserts whole lines:
With GNU sed:
# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile
A portable variant that also works with macOS / BSD sed:
# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile
Note that the literal newline after the \ is required.
If the input file must be edited in place (preserving its inode with all its attributes):
Using the venerable ed POSIX utility:
Note:
ed invariably reads the input file as a whole into memory first.
To prepend directly to the first line (as with sed, this won't work if the input file is completely empty (0 bytes)):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-s suppressed ed's status messages.
Note how the commands are provided to ed as a multi-line here-document (<<EOF\n...\nEOF), i.e., via stdin; by default string expansion is performed in such documents (shell variables are interpolated); quote the opening delimiter to suppress that (e.g., <<'EOF').
1 makes the 1st line the current line
function s performs a regex-based string substitution on the current line, as in sed; you may include literal newlines in the substitution text, but they must be \-escaped.
w writes the result back to the input file (for testing, replace w with ,p to only print the result, without modifying the input file).
To prepend one or more whole lines:
As with sed, the i function invariably adds a trailing newline to the text to be inserted.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 i makes 0 (the beginning of the file) the current line and starts insert mode (i); note that line numbers are otherwise 1-based.
The following lines are the text to insert before the current line, terminated with . on its own line.
This will work to form the output. The - means standard input, which is provide via the pipe from echo.
echo -e "to be prepended \n another line" | cat - text.txt
To rewrite the file a temporary file is required as cannot pipe back into the input file.
echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
Prefer Adam's answer
We can make it easier to use sponge. Now we don't need to create a temporary file and rename it by
echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
Probably nothing built-in, but you could write your own pretty easily, like this:
#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"
Something like that at least...
Editor's note:
This command will result in data loss if the input file happens to be larger than your system's pipeline buffer size, which is typically 64 KB nowadays. See the comments for details.
In some circumstances prepended text may available only from stdin.
Then this combination shall work.
echo "to be prepended" | cat - text.txt | tee text.txt
If you want to omit tee output, then append > /dev/null.
Another way using sed:
sed -i.old '1 {i to be prepended
}' inFile
If the line to be prepended is multiline:
sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
Solution:
printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt
Note that this is safe on all kind of inputs, because there are no expansions. For example, if you want to prepend !##$%^&*()ugly text\n\t\n, it will just work:
printf '%s\n%s' '!##$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt
The last part left for consideration is whitespace removal at end of file during command substitution "$(cat file.txt)". All work-arounds for this are relatively complex. If you want to preserve newlines at end of file.txt, see this: https://stackoverflow.com/a/22607352/1091436
As tested in Bash (in Ubuntu), if starting with a test file via;
echo "Original Line" > test_file.txt
you can execute;
echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt
or, if the version of bash is too old for $(), you can use backticks;
echo "`echo "New Line"; cat test_file.txt`" > test_file.txt
and receive the following contents of "test_file.txt";
New Line
Original Line
No intermediary file, just bash/echo.
Another fairly straight forward solution is:
$ echo -e "string\n" $(cat file)
% echo blaha > blaha
% echo fizz > fizz
% cat blaha fizz > buzz
% cat buzz
blaha
fizz
You can do that easily with awk
cat text.txt|awk '{print "to be prepended"$0}'
It seems like the question is about prepending a string to the file not each line of the file, in this case as suggested by Tom Ekberg the following command should be used instead.
awk 'BEGIN{print "to be prepended"} {print $0}' text.txt
If you like vi/vim, this may be more your style.
printf '0i\n%s\n.\nwq\n' prepend-text | ed file
For future readers who want to append one or more lines of text (with variables or even subshell code) and keep it readable and formatted, you may enjoy this:
echo "Lonely string" > my-file.txt
Then run
cat <<EOF > my-file.txt
Hello, there!
$(cat my-file.txt)
EOF
Results of cat my-file.txt:
Hello, there!
Lonely string
This works because the read of my-file.txt happens first and in a subshell. I use this trick all the time to append important rules to config files in Docker containers rather than copy over entire config files.
you can use variables
Even though a bunsh of answers here work pretty well, I want to contribute this one-liner, just for completeness. At least it is easy to keep in mind and maybe contributes to some general understanding of bash for some people.
PREPEND="new line 1"; FILE="text.txt"; printf "${PREPEND}\n`cat $FILE`" > $FILE
In this snippe just replace text.txt with the textfile you want to prepend to and new line 1 with the text to prepend.
example
$ printf "old line 1\nold line 2" > text.txt
$ cat text.txt; echo ""
old line 1
old line 2
$ PREPEND="new line 1"; FILE="text.txt"; printf "${PREPEND}\n`cat $FILE`" > $FILE
$ cat text.txt; echo ""
new line 1
old line 1
old line 2
$
# create a file with content..
echo foo > /tmp/foo
# prepend a line containing "jim" to the file
sed -i "1s/^/jim\n/" /tmp/foo
# verify the content of the file has the new line prepened to it
cat /tmp/foo
I'd recommend defining a function and then importing and using that where needed.
prepend_to_file() {
file=$1
text=$2
if ! [[ -f $file ]] then
touch $file
fi
echo "$text" | cat - $file > $file.new
mv -f $file.new $file
}
Then use it like so:
prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"
Your file contents will then be:
This is second
This is first
I'm about to use this approach for implementing a change log updater.
With ex,
ex - $file << PREPEND
-1
i
prepended text
.
wq
PREPEND
The ex commands are
-1 Go to the very beginning of the file
i Begin insert mode
. End insert mode
wq Save (write) and quit

unable to run awk command as a shell script

i am trying to create a shell script to search for a specific index in a multiline csv file.
the code i am trying is:
#!/bin/sh
echo "please enter the line no. to search: "
read line
echo "please enter the index to search at: "
read index
awk -F, 'NR=="$line"{print "$index"}' "$1"
the awk command I try to use on the shell works absolutely fine. But when I am trying to create a shell script out of this command, it fails and gives no output. It reads the line no. and index. and then no output at all.
is there something I am doing wrong?
I run the file at the shell by typing:
./fetchvalue.sh newfile.csv
Your quoting is not going to work. Try this:
awk -F, 'NR=="'$line'"{print $'$index'}' "$1"
Rather than going through quoting hell, try this:
awk -F, -v line=$line -v myindex=$index 'NR==line {print $myindex}' "$1"
(Index is a reserved word in awk, so I gave it a slightly differet name)

Resources