bash memo

I always forget the syntax of if…then..else…fi clauses

if test 1 -gt 0 then

echo yes

fi

will produce the error:-bash: syntax error near unexpected token fi'

if test 1 -gt 0 then echo yes

fi

will produce the same error.

The correct notation is:

if test 1 -gt 0

then echo yes

fi

or,

if test 1 -gt 0

then

echo yes

fi

In fact every line (without ; ) will be considered as a sub clause in bash. So if I write "if test 1 -gt 0 then" in one line, that would be a single sub-clause which is not correct in syntax because "if" sub-clause does not allow the occurrence of "then". "then ..." is another sub-clause.  But the following notations are also correct.

if

test 1 -gt 0

then

echo yes

fi

Bash will concatenate the following line to the "if" line to form a sub-clause, if nothing follows the "if" in the "if" line. The same goes with the "then" subclause.

THEN can be followed by only one command. If you write multiple commands after THEN, the other commands except the first one will be considered as the parameters of the first command. This does not mean you cannot achieve the same effect as the compound statement in other programming languages like C because if the condition of the IF statement is satisfied, all commands following the IF command including the THEN command are executed, if the  condition of the IF statement is not satisfied, all commands after the IF command are skipped till the FI command or the  ELSE command.

If you write a wrong syntax, you can use the up arrow to call the last command to see how bash interprets your last command. Bash will show the last command separating each sub-clause with a ;

C programmers often make the following mistake:

if test 1 -gt 0

echo "1>0"

fi

Here, the "THEN" is omitted.

if clause tests the exit code of the command. If the command exits with 0, the then clause is executed.  If you want to execute the then clause when the command exits with a non-zero value, you can add a ! before the command, i.e.,

if ! command;then;fi

Note there is a space between the ! and the command.

The test command evaluates the expression(not  a command)  passed as its parameters and return 0 if the expression is evaluated to true.

test -n "$variable" returns 0 if $variable is not empty.

test -z "$variable" returns 0 if $variable is empty.

test 1 -gt 0 -a 2 -gt 1 returns 0;

test 1 -gt 0 -0 1 -gt 2 returns 0

The above description like those in classical unix books, will give you an illusion that only one condition(a command or test) can be used for the if statement. This is not correct. You can put multiple commands after if using && or ||, which acts like the logical operator "AND","OR".  For example,

if grep aa in file && grep bb in file

then echo "both aa and bb occur in file"

fi

if grep aa in file || grep bb in file

then echo "aa or bb occurs in file"

fi

For &&, the first command is executed and if exit 0, the second command is executed, and IF tests the exit code of the second command to decide whether to execute the THEN sub-clause. If the first command exits non-zero, the second command will not be execute and IF tests the exit value of the first command(non-zero)  so it will not execute the THEN sub-clause.

For ||, the first command is executed and if exits with 0, the second command will not be executed, and IF tests the exit code of the first command(0) and decides to execute the THEN sub-clause. If the first command exits with non-zero, the second command will be executed and IF decides whether to execute the THEN sub-clause according to the exit code of the second command.

] is not a command but [ is a command. The command [ requires a parameter ]. If you don't provide it, [ will complain about "missing ]".  The [ command does the same thing as the test command.

The case sub-clause is more complicated. The case sub-clause expects a IN keyword in it. You can put multiple commands separated by ; after the ) keyword in the case sub-clause. The case command separates the stuff after the IN keyword and before the esac keyword into branches by ";;" A branch is further split into the matched string and the commands to execute by ).

The . is not a wild card character but * and ? are wild card characters matching file names. \ is an escape character but \ is just an ordinary character in "".  If \ has nothing to escape for the character next to it, the \ is swallowed by shell.

$v is expanded even in "", but $v is not expanded in ''.

; is used to separate commands or sub-clauses. If a command includes multiple sub-clauses, the command gets executed only after you input all the sub-clauses.

The FOR sub-clause only includes IN, does not include DO. DO is another sub-clause of the FOR command. DONE is another sub-clause of the FOR command.

In interactive bash environment, after you input something on a line and press enter, shell will check: if what you input is a command, execute that command; if what you input is a complete sub-clause of a command, prompt you to continue to input the remaining sub-clauses after > until all sub-clauses of the command are input, then execute that command; if what you input is recognized as part of a sub-clause such as you input an IF, prompt you to continue to input the remaining part of the sub-clause after >. If what you input is neither a command, nor a subclause, not part of sub-clause, print "-bash: xxx: command not found". The interactive bash will check the syntax error as early as possible so if you input FOR then press enter, it will show the error "-bash: syntax error near unexpected token newline’” before for cannot be followed by a newline(I do not know why).

 

sed global replace: sed  “s/aaa/bbb/g” file , global means in whole line, not whole file. Even without the g, sed will handle all lines in the file. With the g, sed will replace all occurrences in a line, otherwise, sed only replaces the first occurrence in a line.

sed -n “2,3p” file: select the second and the third line of the file. -n means no automatic output. p is the processing command. A line is processed then printed automatically without -n.

cut -f 2 -d ‘ ‘ : cut the second field of a line. The fields are separated by ‘ ‘.

awk ‘{print $5}’ : print the fifth field of a line.

 

 

Posted in tips of hosting