How To Test bash expression
Bash expression are deemed to be true or false by the test command or one of two nonstandard shell reserved words, [[ and ((. The test command compares strings, integers, and various file attributes; (( tests arithmetic expressions, and [[ … ]] does the same as test with the additional feature of comparing regular bash expression.
test, aka [ ... ]
The test command evaluates many kinds of expressions, from file properties to integers to strings. It is a built-in command, and therefore its arguments are expanded just as for any other command. The alternative version ([) requires a closing bracket at the end.
File Tests
Several operators test the state of a file. A file’s existence can be tested with -e (or the nonstandard -a). The type of file can be checked with -f for a regular file, -d for a directory, and -h or -L for a symbolic link. Other operators test for special types of files and for which permission bits are set.
Here are some examples:
test -f /etc/fstab ## true if a regular file test -h /etc/rc.local ## true if a symbolic link [ -x $HOME/bin/hw ] ## true if you can execute the file
Integer Tests
Comparisons between integers use the -eq, -ne, -gt, -lt, -ge, and -le operators.
The equality of integers is tested with -eq:
$ test 1 -eq 1 $ echo $? 0 $ [ 2 -eq 1 ] $ echo $? 1
Inequality is tested with -ne:
$ [ 2 -ne 1 ] $ echo $? 0
The remaining operators test greater than, less than, greater than or equal to, and less than or equal to.
String Tests
Strings are concatenations of zero or more characters and can include any character except NUL (ASCII 0). They can be tested for equality or inequality, for nonempty string or null string, and in bash for alphabetical ordering. The = operator tests for equality, in other words, whether they are identical; != tests for inequality. bash also accepts == for equality, but there is no reason to use this nonstandard operator.
Here are some examples:
test "$a" = "$b" [ "$q" != "$b" ]
The -z and -n operators return successfully if their arguments are empty or nonempty:
$ [ -z "" ] $ echo $? 0 $ test -n "" $ echo $? 1
The greater-than and less-than symbols are used in bash to compare the lexical positions of strings and must be escaped to prevent them from being interpreted as redirection operators:
$ str1=abc $ str2=def $ test "$str1" \< "$str2" $ echo $? 0 $ test "$str1" \> "$str2" $ echo $? 1
The previous tests can be combined in a single call to test with the -a (logical AND) and -o (logical
OR operators:
test -f /path/to/file -a $test -eq 1 test -x bin/file -o $test -gt 1
test is usually used in combination with if or the conditional operators && and ||.
[[ … ]]: Evaluate an Expression
Like test, [[ … ]] evaluates an expression. Unlike test, it is not a built-in command. It is part of the shell grammar and not subject to the same parsing as a built-in command. Parameters are expanded, but word splitting and file name expansion are not performed on words between [[ and ]].
It supports all the same operators as test, with some enhancements and additions. It is, however, nonstandard, so it is better not to use it when test could perform the same function.
Enhancements over Test
When the argument to the right of = or != is unquoted, it is treated as a pattern and duplicates the functionality of the case command.
The feature of [[ … ]] that is not duplicated elsewhere in the shell is the ability to match an extended regular expression using the =~ operator:
$ string=whatever $ [[ $string =~ h[aeiou] ]] $ echo $? 0 $ [[ $string =~ h[sdfghjkl] ]] $ echo $? 1
(( … )): Evaluate an Arithmetic Expression
A nonstandard feature, (( arithmetic expression )) returns false if the arithmetic expression
evaluates to zero and returns true otherwise. The portable equivalent uses test and the POSIX syntax for shell arithmetic:
test $(( $a - 2 )) -ne 0
Lists
A list is a sequence of one or more commands separated by semicolons, ampersands, control operators, or newlines. A list may be used as the condition in a while or until loop or as the body of any loop. The exit code of a list is the exit code of the last command in the list.
Conditional execution
Conditional constructs enable a script to decide whether to execute a block of code or to select which of two or more blocks to execute.
if
The basic if command evaluates a list of one or more commands and executes a list if the execution of
ifthen fi
Usually, the
Read and Check Input
read name if [ -z "$name" ] then echo "No name entered" >&2 exit 1 ## Set a failed return code fi
Using the else keyword, a different set of commands can be executed if the
Prompt for a Number and Check That It Is No Greater Than Ten
printf "Enter a number no greater than 10: " read number if [ "$number" -gt 10 ] then else fi printf "%d is too big\n" "$number" >&2 exit 1 printf "You entered %d\n" "$number"
More than one condition can be given, using the elif keyword, so that if the first test fails, the second is tried, as shown in Listing 3-3.
Prompt for a Number and Check That It Is Within a Given Range
printf "Enter a number between 10 and 20 inclusive: " read number if [ "$number" -lt 10 ] then printf "%d is too low\n" "$number" >&2 exit 1 elif [ "$number" -gt 20 ] then else fi printf "%d is too high\n" "$number" >&2 exit 1 printf "You entered %d\n" "$number"
Often more than one test is given in the
Conditional Operators, && and ||
Lists containing the AND and OR conditional operators are evaluated from left to right. A command following the AND operator (&&) is executed if the previous command is successful. The part following the OR operator (||) is executed if the previous command fails.
For example, to check for a directory and cd into it if it exists, use this:
test -d "$directory" && cd "$directory"
To change directory and exit with an error if cd fails, use this:
cd "$HOME/bin" || exit 1
The next command tries to create a directory and cd to it. If either mkdir or cd fails, it exits with an error:
mkdir "$HOME/bin" && cd "$HOME/bin" || exit 1
Conditional operators are often used with if. In this example, the echo command is executed if both tests are successful:
if [ -d "$dir" ] && cd "$dir" then echo "$PWD" fi
case
A case statement compares a word (usually a variable) against one or more patterns and executes the commands associated with that pattern. The patterns are pathname expansion patterns using wildcards (* and ?) and character lists and ranges ([…]). The syntax is as follows:
case WORD in PATTERN) COMMANDS ;; PATTERN) COMMANDS ;; ## optional esac
A common use of case is to determine whether one string is contained in another. It is much faster than using grep, which creates a new process. This short script would normally be implemented as a shell function so that it will be executed without creating a new process, as shown in Listing 3-4.
Does One String Contain Another?
case $1 in *"$2"*) true ;; *) false ;; esac
The commands, true and false, do nothing but succeed or fail, respectively.
Another common task is to check whether a string is a valid number. Again, Listing 3-5 would usually be implemented as a function.
Is This a Valid Integer?
case $1 in *[!0-9]*) false;; *) true ;; esac
Many scripts require one or more arguments on the command line. To check whether there are the correct number, case is often used:
case $# in 3) ;; ## We need 3 args, so do nothing *) printf "%s\n" "Please provide three names" >&2 exit 1 ;; esac
Looping
When a command or series of commands needs to be repeated, it is put inside a loop. The shell provides three types of loop: while, until, and for. The first two execute until a condition is either true or false;
the third loops through a list of words.
while
The condition for a while loop is a list of one or more commands, and the commands to be executed while the condition remains true are placed between the keywords do and done:
whiledo
done
By incrementing a variable each time the loop is executed, the commands can be run a specific number of times:
n=1 while [ $n -le 10 ] do echo "$n" n=$(( $n + 1 )) done
The true command can be used to create an infinite loop:
while true ## : can be used in place of true do read x done
A while loop can be used to read line by line from a file:
while IFS= read -r line do : do something with "$line" done < FILENAMEy? until
Rarely used, until loops as long as the condition fails. It is the opposite of while:
n=1 until [ $n -gt 10 ] do echo "$n" n=$(( $n + 1 )) done
for
At the top of a for loop, a variable is given a value from a list of words. On each iteration, the next word in the list is assigned:
for var in Canada USA Mexico do printf "%s\n" "$var" done
bash also has a nonstandard form that is similar to that found in the C programming language. The first expression is evaluated when first encountered. The second is a test. The third is evaluated after each iteration:
for (( n=1; n< =10; ++n )) do echo "$n" done
Since this offers no advantage over standard looping methods, it is not used in this book.
break
A loop can be exited at any point with the break command:
while : do read x [ -z "$x" ] && break Done
With a numeric argument, break can exit multiple nested loops:
for n in a b c d e do while true do if [ $RANDOM -gt 20000 ] then printf . break 2 ## break out of both while and for loops elif [ $RANDOM -lt 10000 ] then printf '"' break ## break out of the while loop fi done done echo
continue
Inside a loop, the continue command immediately starts a new iteration of the loop, bypassing any remaining commands:
for n in {1..9} ## See Brace expansion in Chapter 4 do x=$RANDOM [ $x -le 20000 ] && continue echo "n=$n x=$x" Done
Commands
x test: Evaluates an expression and returns success or failure x if: Executes a set of command if a list of commands is successful and optionally executes a different set if it is not x case: Matches a word with one or more patterns and executes the commands associated with the first matching pattern x while: Repeatedly executes a set of commands while a list of commands executes successfully x until: Repeatedly executes a set of commands until a list of commands executes successfully x for: Repeatedly executes a set of commands for each word in a list x break: Exits from a loop x continue: Starts the next iteration of a loop immediately
In case of any ©Copyright or missing credits issue please check CopyRights page for faster resolutions.