The [[...]] command is used to evaluate conditional expressions with file attributes, strings, integers, and more. The basic format is:
[[expression]]
where expression is the condition you are evaluating. There must be whitespace after the opening brackets, and before the closing brackets. Whitespace must also separate the expression arguments and operators. For example, these are incorrect:
[[$X=$Y]] [[$X = $Y]]
while this is correct:
[[ $X == $Y ]]
Notice that there is white space between $X, $Y, and the = operator.
If the expression evaluates to true, then a zero exit status is returned, otherwise the expression evaluates to false and a non-zero exit status is returned.
If you are familiar with the test and [...] commands, then you'll recognize that [[...]] is just a new and improved version of the same commands. It basically functions the same way, except that a number of new operators are available.
–n string | true if length of string is not zero |
–o option | true if option is set |
–z string | true if length of string is zero |
string1 = string2 | true if string1 is equal to string2 |
string1 != string2 | true if string1 is not equal to string2 |
string = pattern | true if string matches pattern |
string != pattern | true if string does not match pattern |
string1 < string2 | true if string1 less than string2 |
string1 > string2 | true if string1 greater than string2 |
We could use the [[...]] command to check if a variable is set to a certain value. Here, variable X is assigned abc, then evaluated in this expression:
$ X=abc $ [[ $X = abc ]] && print "X is set to abc" X is set to abc
Using the test and [...] commands, the same command could be written as:
test "$X" = abc && print "X is set to abc"
or
[ "$X" = abc ] && print "X is set to abc"
To check if a variable is set to null, the –z option can be used:
[[ —z $VAR ]] && print "VAR is set to null"
or it could be compared to the null string like this:
[[ $VAR = "" ]] && "VAR is set to null"
The Korn shell also lets you compare strings to patterns. We could check if X begins with a 'a' like this:
$ X=abc $ [[ $X = a* ]] && print "$X matches a*" abc matches a*
or if it's a three-character string:
$ [[ $X = ??? ]] && print "$X has exactly 3 characters" abc has exactly 3 characters
Using the +([0–9]) pattern, we could check if X is set to a number:
$ X=123 $ [[ $X = +([0—9]) ]] && print "$X is a number" 123 is a number
Table 8.2 lists the most commonly used [[...]] string operators.
–a file | true if file exists. |
–d file | true if file exists and is a directory. |
–f file | true if file exists and is a regular file. |
–G file | true if file exists and its group id matches the effective group id of the current process. |
–L file | true if file exists and is a symbolic link. |
–Ofile | true if file exists and its user id matches the effective user id of the current process. |
–r file | true if file exists and is readable. |
–s file | true if file exists and its size is greater than zero. |
–S file | true if file exists and is a socket. |
–u file | true if file exists and its set user-id bit is set. |
–w file | true if file exists and is writable. |
–x file | true if file exists and is executable. If file is a directory, then true indicates that the directory is searchable. |
file1 –ef file2 | true if file1 exists and is another name for file2. |
file1 –nt file2 | true if file1 exists and is newer than file2. |
file1 – ot file2 | true if file1 exists and is older than file2. |
Because manipulating files is so important in programming, the Korn shell provides a whole range of file operators. The most basic operation to perform on a file is to see if it exists, and that can be done using the –a operator. This is a new Korn shell file operator. Make sure you don't get it confused with the logical AND operator used by the test and [...] commands, which is also written as –a.
$ touch tmp $ [[ —a tmp ]] && print "File tmp exists" File tmp exists
This only indicates that it exists, but not much else. It may be a directory, or a symbolic link, but using this operator, that's all we know. If we wanted more information, the –f or –d operators could tell us if a file existed and was a normal file (–f) or if it was just a directory (–d). Let's try the –f operator on the tmp file:
$ [[ –f tmp ]] && print "File tmp exists and is a regular file" File tmp exists and is a regular file
If we tried the –d operator on the tmp file, it would evaluate to false, because it isn't a directory:
$ [[ –d tmp ]] && print "File tmp exists and is a regular file" $
While on a directory it would evaluate to true:
$ mkdir tmpdir $ [[ –d tmpdir ]] && print "Directory tmp exists" Directory tmp exists
This conditional command checks if $FILE is readable, and if not, prints an error message and exits:
[[ –r $FILE ]]||{ print $FILE not readable; exit 1; }
while this one checks if $FILE is writable:
[[ –w $FILE ]]||{ print $FILE not writable; exit 1; }
Here are a couple of new file operators: –nt and –ot. They compare two files and return true if file1 is newer than (–nt) or older than (–ot) file2.
$ touch tfile2 $ touch tfile1 $ [[ tfile1 —nt tfile2 ]]&&print "tfile1 is newer than tfile2" tfile1 is newer than tfile2
Let's switch the files in the expression and try the –ot operator:
$ [[ tfile2 —ot tfile1 ]]&&print "tfile2 is older than tfile1" tfile2 is older than tfile1
Table 8.3 lists the most commonly used [[...]] file operators.
The [[...]] command provides a few integer operators that allow integers to be compared. It is frequently used to check the number of command-line arguments. This expression evaluates to true if there are less than or equal to three positional parameters set:
[[ $# —le 3 ]] && print "3 or less args given"
The last expression is equivalent to checking if there are less than four positional parameters set:
[[ $# —lt 4 ]] && print "Less than 4 args given"
The number of users logged on could be checked like this:
$ [[ $(who | wc —l) —gt 10 ]] && print "More than 10 users are logged on" More than 10 users are logged on
In many cases, the [[...]] integer operators may be sufficient for evaluating expressions that contain integers. To perform other arithmetic operations, use the ((...)) command (discussed in Chapter 6). It offers the same arithmetic comparison operators as the [[...]] command, plus many others. Besides offering more arithmetic operators, the ((...)) command provides substantial performance improvements over the [[...]] and test commands. The last command could also be given as:
(($(who | wc —l) > 10)) && print "More than 10 users are logged on"
Using an arithmetic expression, the number of command-line arguments can be checked like this:
(($# < 4)) && print "Less than 4 args"
Table 8.4 lists the most commonly used [[...]] integer operators.
The ! operator negates the result of any [[...]] expression when used like this:
[[ ! expression]]
For example, to check if X is not equal to abc:
$ X=xyz $ [[ ! $X = abc ]] && print "$X not equals abc" xyz not equals abc
or if a file doesn't exist:
$ rm tmp $ [[ ! —f tmp ]] && print "tmp does NOT exist" tmp does NOT exist
exp1 –eq exp2 | true if exp1 is equal to exp2 |
exp1 –ne exp2 | true if exp1 is not equal to exp2 |
exp1 –le exp2 | true if exp1 is less than or equal to exp2 |
exp1 –lt exp2 | true if exp1 is less than exp2 |
exp1 –ge exp2 | true if exp1 is greater than or equal to exp2 |
exp1 –gt exp2 | true if exp1 is greater than exp2 |
There is one logical operator that can only be implemented with the ! operator. There is no [[...]] file operator that will evaluate to true on a zero-length file.
$ >emptyfile $ [[ ! —s emptyfile ]] && print "emptyfile is empty" emptyfile is empty
Expressions can also be combined with the && and || operators to form compound expressions.
The && operator is used with the [[...]] command to test if multiple expressions are true using this format:
[[expression1 && expression2]]
We could check if two variables were set to specific values like this:
$ X=abc Y=def $ [[ $X = abc && $Y = def ]] && print "X=abc and Y=def" X=abc and Y=def
This expression checks if the noglob and noclobber options are set:
[[ —o noglob && —o noclobber ]]
Multiple && operators can also be given in one [[...]] command. We could check if three options were set like this:
[[ —o noglob && —o noclobber && —o bgnice ]]
In some versions of the Korn shell, multiple && operators cannot be given in one [[...]] command unless grouped with parentheses.
The || operator is used with the [[...]] command to test if expression1 OR expression2 are true using this format:
[[expression1 || expression2]]
This expression checks if $FILE was readable or executable:
[[ —r $FILE || —w $FILE ]]
while this one checks if either variable was set to your name:
[[ $USER=$(whoami) || $LOGNAME=$(whoami) ]]
Multiple || operators can also be given in one [[...]] command. We could check if $FILE was readable, writable, or executable like this:
[[ —r $FILE || —w $FILE || —x $FILE ]]
As with the && operator, in some versions of the Korn shell, multiple || operators cannot be given in one [[...]] command unless grouped with parentheses.
The [[...]] command is preferred to test and [...], since many of the errors associated with test and [...] do not occur. For example, when comparing two variables where one is set to null or unset, the test and [...] commands return a syntax error if the variable is not surrounded in double quotes. Here, X is unset, while Y is set to 1:
$ unset X $ Y=1
Without double quotes around the variable names, the test and [...] commands return a syntax error:
$ test $X = $Y && print "X and Y are equal" /bin/ksh: test: argument expected
or
$ [ $X = $Y ] && print "X and Y are equal" /bin/ksh: test: argument expected
while the [[...]] command does not (unless the nounset option is enabled):
$ [[ $X = $Y ]] && print "X and Y are equal" X and Y are equal
On systems that support the /dev/fd directory for naming open files, the files argument in expressions can be given as /dev/fd/n so that the test is applied to the open file associated with file descriptor n. This command checks to see if standard input (file descriptor 0) is readable:
$ [[ —r /dev/fd/0 ]] && print "Stdin is readable" Stdin is readable
3.135.199.27