The and list and or list constructs provide a means of processing a number of commands consecutively. These can effectively replace complex nested if/then or even case statements.
1 command-1 && command-2 && command-3 && ... command-n |
An interesting use of a two-condition and list from an early version of YongYe's Tetris game script:
1 equation() 2 3 { # core algorithm used for doubling and halving the coordinates 4 [[ ${cdx} ]] && ((y=cy+(ccy-cdy)${2}2)) 5 eval ${1}+=\"${x} ${y} \" 6 } |
Example 26-1. Using an and list to test for command-line arguments
1 #!/bin/bash 2 # and list 3 4 if [ ! -z "$1" ] && echo "Argument #1 = $1" && [ ! -z "$2" ] && \ 5 # ^^ ^^ ^^ 6 echo "Argument #2 = $2" 7 then 8 echo "At least 2 arguments passed to script." 9 # All the chained commands return true. 10 else 11 echo "Fewer than 2 arguments passed to script." 12 # At least one of the chained commands returns false. 13 fi 14 # Note that "if [ ! -z $1 ]" works, but its alleged equivalent, 15 # "if [ -n $1 ]" does not. 16 # However, quoting fixes this. 17 # if "[ -n "$1" ]" works. 18 # ^ ^ Careful! 19 # It is always best to QUOTE the variables being tested. 20 21 22 # This accomplishes the same thing, using "pure" if/then statements. 23 if [ ! -z "$1" ] 24 then 25 echo "Argument #1 = $1" 26 fi 27 if [ ! -z "$2" ] 28 then 29 echo "Argument #2 = $2" 30 echo "At least 2 arguments passed to script." 31 else 32 echo "Fewer than 2 arguments passed to script." 33 fi 34 # It's longer and more ponderous than using an "and list". 35 36 37 exit $? |
Example 26-2. Another command-line arg test using an and list
1 #!/bin/bash 2 3 ARGS=1 # Number of arguments expected. 4 E_BADARGS=85 # Exit value if incorrect number of args passed. 5 6 test $# -ne $ARGS && \ 7 # ^^^^^^^^^^^^ condition #1 8 echo "Usage: `basename $0` $ARGS argument(s)" && exit $E_BADARGS 9 # ^^ 10 # If condition #1 tests true (wrong number of args passed to script), 11 #+ then the rest of the line executes, and script terminates. 12 13 # Line below executes only if the above test fails. 14 echo "Correct number of arguments passed to this script." 15 16 exit 0 17 18 # To check exit value, do a "echo $?" after script termination. |
Of course, an and list can also set variables to a default value.
1 arg1=$@ && [ -z "$arg1" ] && arg1=DEFAULT 2 3 # Set $arg1 to command-line arguments, if any. 4 # But . . . set to DEFAULT if not specified on command-line. |
1 command-1 || command-2 || command-3 || ... command-n |
Example 26-3. Using or lists in combination with an and list
1 #!/bin/bash 2 3 # delete.sh, a not-so-cunning file deletion utility. 4 # Usage: delete filename 5 6 E_BADARGS=85 7 8 if [ -z "$1" ] 9 then 10 echo "Usage: `basename $0` filename" 11 exit $E_BADARGS # No arg? Bail out. 12 else 13 file=$1 # Set filename. 14 fi 15 16 17 [ ! -f "$file" ] && echo "File \"$file\" not found. \ 18 Cowardly refusing to delete a nonexistent file." 19 # AND LIST, to give error message if file not present. 20 # Note echo message continuing on to a second line after an escape. 21 22 [ ! -f "$file" ] || (rm -f $file; echo "File \"$file\" deleted.") 23 # OR LIST, to delete file if present. 24 25 # Note logic inversion above. 26 # AND LIST executes on true, OR LIST on false. 27 28 exit $? |
If the first command in an or list returns true, it will execute. |
1 # ==> The following snippets from the /etc/rc.d/init.d/single 2 #+==> script by Miquel van Smoorenburg 3 #+==> illustrate use of "and" and "or" lists. 4 # ==> "Arrowed" comments added by document author. 5 6 [ -x /usr/bin/clear ] && /usr/bin/clear 7 # ==> If /usr/bin/clear exists, then invoke it. 8 # ==> Checking for the existence of a command before calling it 9 #+==> avoids error messages and other awkward consequences. 10 11 # ==> . . . 12 13 # If they want to run something in single user mode, might as well run it... 14 for i in /etc/rc1.d/S[0-9][0-9]* ; do 15 # Check if the script is there. 16 [ -x "$i" ] || continue 17 # ==> If corresponding file in $PWD *not* found, 18 #+==> then "continue" by jumping to the top of the loop. 19 20 # Reject backup files and files generated by rpm. 21 case "$1" in 22 *.rpmsave|*.rpmorig|*.rpmnew|*~|*.orig) 23 continue;; 24 esac 25 [ "$i" = "/etc/rc1.d/S00single" ] && continue 26 # ==> Set script name, but don't execute it yet. 27 $i start 28 done 29 30 # ==> . . . |
The exit status of an and list or an or list is the exit status of the last command executed. |
Clever combinations of and and or lists are possible, but the logic may easily become convoluted and require close attention to operator precedence rules, and possibly extensive debugging.
1 false && true || echo false # false 2 3 # Same result as 4 ( false && true ) || echo false # false 5 # But NOT 6 false && ( true || echo false ) # (nothing echoed) 7 8 # Note left-to-right grouping and evaluation of statements. 9 10 # It's usually best to avoid such complexities. 11 12 # Thanks, S.C. |
See Example A-7 and Example 7-4 for illustrations of using and / or list constructs to test variables.