The [[...]] Command





The [[...]] Command

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.

[[...]] String Operators

–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

Checking Strings

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" 
Checking Patterns

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?]) pattern, we could check if X is set to a number:

$ X=123 
$ [[ $X = +([0?]) ]] && print "$X is a number" 
123 is a number 

Figure lists the most commonly used [[...]] string operators.

Some [[...]] File 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.

Checking File Attributes

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 ?span class="docEmphStrong">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 ?span class="docEmphStrong">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 

Figure lists the most commonly used [[...]] file operators.

Checking Integer Attributes

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" 

Figure lists the most commonly used [[...]] integer operators.

The ! Operator

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 

[[...]] Integer Operators

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 

Compound Expressions

Expressions can also be combined with the && and || operators to form compound expressions.

&& - The AND Operator

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.

Other [[...]] Operators

[[expression1 && expression2]]

true if both expression1 and expression2 are true

[[expression1 || expression2]]

true either expression1 or expression2 are true

[[(expression)]]

true if expression evaluates to true. The ()'s are used to override the precedence rules.

[[ !expression]]

true if expression evaluates to false

|| - The OR Operator

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.

[[...]] vs test and [...]

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 

Checking File Descriptors

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 


     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows