The builtin test operator

February 5, 2009


In bash (and other shells) you can use the [[ construct

From the bash manpage:

[[ expression ]]
          Return a status of 0 or 1 depending on  the  evaluation  of  the
          conditional  expression expression.  Expressions are composed of
          the primaries described  below  under  CONDITIONAL  EXPRESSIONS.

          Word  splitting  and pathname expansion are not performed on the

          words between the [[ and  ]];  tilde  expansion,  parameter  and
          variable  expansion, arithmetic expansion, command substitution,
          process substitution, and quote removal are  performed.   Condi‐
          tional operators such as -f must be unquoted to be recognized as

So no word splitting and pathname expansion.

A little example

First we have some setting up to do

$ mkdir ~/tmp/zz
$ touch ~/tmp/zz/111
$ echo ~/tmp/zz/*

Well, lets test [[

$ if [[  tmp/zz/* = tmp/zz/111 ]]; then echo OK; else echo NOK; fi

NOK - that’s correct, because [[ will not do pathname expansion.

The other way around

$ if [[  tmp/zz/111 = tmp/zz/* ]]; then echo OK; else echo NOK; fi

Huh, OK?

Why To see why bash behaves as it does, the best explanation comes from the ksh manual. Yes, the K shell. In the section ‘Conditional Expressions’ of ksh’s manual page

string = pattern        True, if string matches pattern.

Aha, so the right side of a = test is a pattern and a such it is expanded even though we put it in a [[ construct.

In the bash manual we just have

string1 == string2
True if the strings are equal.  = may be used
in place of == for strict POSIX compliance.

Which is not entirely correct.

In zsh (which is of course the shell) in the section ‘CONDITIONAL EXPRESSIONS’ it is also correct

string = pattern
string == pattern
    true if string matches pattern.  The ‘==’ form is the  preferred
    one.   The  ‘=’ form is for backward compatibility and should be
    considered obsolete.

So this might be something worth considering.