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 |
Example 25-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 && echo "Argument #2 = $2" 6 then 7 echo "At least 2 arguments passed to script." 8 # All the chained commands return true. 9 else 10 echo "Less than 2 arguments passed to script." 11 # At least one of the chained commands returns false. 12 fi 13 # Note that "if [ ! -z $1 ]" works, but its supposed equivalent, 14 # if [ -n $1 ] does not. 15 # However, quoting fixes this. 16 # if [ -n "$1" ] works. 17 # Careful! 18 # It is always best to QUOTE tested variables. 19 20 21 # This accomplishes the same thing, using "pure" if/then statements. 22 if [ ! -z "$1" ] 23 then 24 echo "Argument #1 = $1" 25 fi 26 if [ ! -z "$2" ] 27 then 28 echo "Argument #2 = $2" 29 echo "At least 2 arguments passed to script." 30 else 31 echo "Less than 2 arguments passed to script." 32 fi 33 # It's longer and less elegant than using an "and list". 34 35 36 exit 0 |
Example 25-2. Another command-line arg test using an and list
1 #!/bin/bash 2 3 ARGS=1 # Number of arguments expected. 4 E_BADARGS=65 # Exit value if incorrect number of args passed. 5 6 test $# -ne $ARGS && \ 7 echo "Usage: `basename $0` $ARGS argument(s)" && exit $E_BADARGS 8 # If condition 1 tests true (wrong number of args passed to script), 9 #+ then the rest of the line executes, and script terminates. 10 11 # Line below executes only if the above test fails. 12 echo "Correct number of arguments passed to this script." 13 14 exit 0 15 16 # 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 25-3. Using or lists in combination with an and list
1 #!/bin/bash 2 3 # delete.sh, not-so-cunning file deletion utility. 4 # Usage: delete filename 5 6 E_BADARGS=65 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 continued on to a second line with 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 0 |
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 #+ since the logic operators "&&" and "||" have equal precedence. 10 11 # It's best to avoid such complexities, unless you know what you're doing. 12 13 # Thanks, S.C. |
See Example A-7 and Example 7-4 for illustrations of using an and / or list to test variables.