Advanced Bash-Scripting HOWTO: A guide to shell scripting, using Bash | ||
---|---|---|
Prev | Chapter 3. Tutorial / Reference | Next |
The if/then construct tests whether a condition is true, and if so, executes one or more commands. Note that in this context, 0 (zero) will evaluate as true, as will a random string of alphanumerics. Puzzling out the logic of this is left as an exercise for the reader.
Example 3-9. What is truth?
#!/bin/bash if [ 0 ] #zero then echo "0 is true." else echo "0 is false." fi if [ ] #NULL (empty condition) then echo "NULL is true." else echo "NULL is false." fi if [ xyz ] #string then echo "Random string is true." else echo "Random string is false." fi if [ $xyz ] #string then echo "Undeclared variable is true." else echo "Undeclared variable is false." fi exit 0 |
Exercise. Explain the behavior of Example 3-9, above.
if [ condition-true ] then command 1 command 2 ... else # Optional (may be left out if not needed). # Adds default code block executing if original condition # tests false. command 3 command 4 ... fi |
Add a semicolon when 'if' and 'then' are on same line.
if [ -x filename ]; then |
This is a contraction for else if. The effect is to nest an inner if/then construction within an outer one.
if [ condition ] then command command command elif # Same as else if then command command else default-command fi |
The test condition-true construct is the exact equivalent of if [condition-true ]. The left bracket [ is, in fact, an alias for test. (The closing right bracket ] in a test should not therefore be strictly necessary, however newer versions of bash detect it as a syntax error and complain.)
Example 3-10. Equivalence of [ ] and test
#!/bin/bash echo if test -z $1 then echo "No command-line arguments." else echo "First command-line argument is $1." fi # Both code blocks are functionally identical. if [ -z $1 ] # if [ -z $1 # also works, but outputs an error message. then echo "No command-line arguments." else echo "First command-line argument is $1." fi echo exit 0 |
Returns true if...
file exists
file is a regular file
file is not zero size
file is a directory
file is a block device (floppy, cdrom, etc.)
file is a character device (keyboard, modem, sound card, etc.)
file is a pipe
file is a symbolic link
file is a socket
file is readable (has read permission)
file has write permission
file has execute permission
group-id flag set on file
user-id flag set on file
"sticky bit" set (if user does not own a directory that has the sticky bit set, she cannot delete files in it, not even files she owns)
you are owner of file
group-id of file same as yours
file descriptor n is open
This usually refers to stdin, stdout, and stderr (file descriptors 0 - 2).
file f1 is newer than f2
file f1 is older than f2
files f1 and f2 are links to the same file
"not" -- reverses the sense of the tests above (returns true if condition absent).
Example 3-11. Tests, command chaining, redirection
#!/bin/bash # This line is a comment. filename=sys.log if [ ! -f $filename ] then touch $filename; echo "Creating file." else cat /dev/null > $filename; echo "Cleaning out file." fi # Of course, /var/log/messages must have # world read permission (644) for this to work. tail /var/log/messages > $filename echo "$filename contains tail end of system log." exit 0 |
integer comparison
is equal to ($a -eq $b)
is not equal to ($a -ne $b)
is greater than ($a -gt $b)
is greater than or equal to ($a -ge $b)
is less than ($a -lt $b)
is less than or equal to ($a -le $b)
string comparison
is equal to ($a = $b)
is not equal to ($a != $b)
is less than, in ASCII alphabetical order ($a \< $b)
Note that the "<" needs to be escaped.
is greater than, in ASCII alphabetical order ($a \> $b)
Note that the ">" needs to be escaped.
See Example 3-73 for an application of this comparison operator.
string is "null", that is, has zero length
string in not "null". Note that this test does not work reliably (a bash bug?). Use ! -z instead.
Example 3-12. arithmetic and string comparisons
#!/bin/bash a=4 b=5 # Here a and b can be treated either as integers or strings. # There is some blurring between the arithmetic and integer comparisons. # Be careful. if [ $a -ne $b ] then echo "$a is not equal to $b" echo "(arithmetic comparison)" fi echo if [ $a != $b ] then echo "$a is not equal to $b." echo "(string comparison)" fi echo exit 0 |
Example 3-13. zmost
#!/bin/bash #View gzipped files with 'most' NOARGS=1 if [ $# = 0 ] # same effect as: if [ -z $1 ] then echo "Usage: `basename $0` filename" >&2 # Error message to stderr. exit $NOARGS # Returns 1 as exit status of script # (error code) fi filename=$1 if [ ! -f $filename ] then echo "File $filename not found!" >&2 # Error message to stderr. exit 2 fi if [ ${filename##*.} != "gz" ] # Using bracket in variable substitution. then echo "File $1 is not a gzipped file!" exit 3 fi zcat $1 | most exit 0 # Uses the file viewer 'most' # (similar to 'less') |
compound comparison
logical and
exp1 -a exp2 returns true if both exp1 and exp2 are true.
logical or
exp1 -o exp2 returns true if either exp1 or exp2 are true.
These are simpler forms of the comparison operators && and ||, which require brackets to separate the target expressions.
Refer to Example 3-14 to see compound comparison operators in action.