How to raise and take care of shell scripts: True and False
What is true, what is false?
I already wrote about the exit code of programs in the Errors chapter. The conclusion (0 = o.k., not equal to 0 = error) is also valid when you evaluate expressions: 0 = true, not equal to 0 = false. The shell builtin test works exactly this way: It returns 0, if the tested expression is true, 1 otherwise. Try it:
jan@jack:~/tmp> test 1 -eq 1 jan@jack:~/tmp> echo $? 0 jan@jack:~/tmp> test 1 -eq 2 jan@jack:~/tmp> echo $? 1
So it's without problems possible to use the exit code of programs directly for example in "if-then-else" tests or as exit conditions in loops. Such control structures also evaluate, whether their argument is zero or not. Often one looks at constructs, which are unnecessary complicated and could be written much simplier:
# check if a file contains a defined search pattern # ugly if test `grep pattern file | wc -l` -gt 0; then ... fi # simple if grep -q pattern file; then ... fi # loop as long as there exist -bak files # ugly while true; do num_bak_files=`ls *.bak 2>/dev/null | wc -l` test $num_bak_files -eq 0 && break ... done # simple while ls *.bak >/dev/null 2>>&1; do ... done
By the way: The true used within the while loop is a shell builtin, which always returns 0, it's counterpart is - exactly - false.
Last but not least: In my examples I sometimes used constructs like :
command1 && command2 or
command1 || command2
To tell the truth these are simply AND resp. OR conditions. They use the fact, that the shell is as lazy as most programmers:
- An AND condition is true only if both operands (the exit codes of both commands in my example) are true (=0). If command1 ends with an exit code not equal to 0 (= error), then it's obviously, that the command2's exit code will never have an influence to the result. So it is ignored (the command is not executed). As a result command2 is executed only if command1 succeeded.
- An OR is true if at least one of it's operands is true (=0). If command1 returned with zero, then the condition must be true. In this case command2 will not be executed, because it's exit code does not take effect on the result. Only if command1 fails (returns an exit code not equal to zero), command2 has to be evaluated (executed) to get the condition's result.
As a result, one has to be careful using the result of one of these constructs: It's not clear in all cases. Only if the result of an AND condition is true, you can assume that both commands succeeded. If the result is false, you don't know, which of the commands failed. For the OR condition it's exactly the other way: Only when it's result is false you know, that both commands failed. If the result is true, you can't find out, which command succeeded or if both of them did return true.