There are huge differences between ksh
(and bash
) test expression
and [ expression ]
versus [[ expression ]]
.
The test
and [
are the names of utilities (usually the same physical utility and almost always implemented as shell built-ins). But [[
and ]]
are keywords in the Korn shell's grammar; not commands to be invoked.
In the following examples, assume that a script starts with:
#!/bin/ksh
op="-$1"
file="$2"
exp="$op $file"
(similar to what you had in your initial post), and continues with the commands included in the examples.
Example 1:
The commands:
if test "$exp";then echo true;else echo false;fi
if [ "$exp" ];then echo true;else echo false;fi
will both ALWAYS print true
. Since the expansion of $exp
is quoted, a single string is being passed to test
. Therefore, this will test whether or not $exp
expands to an empty string. Since it contains at least two characters, it is not an empty string. Therefore, it evaluates to true. These commands are logically treated as identical to the commands:
if test -n "$exp";then echo true;else echo false;fi
if [ -n "$exp" ];then echo true;else echo false;fi
Example 2:
Without the quotes:
if test $exp;then echo true;else echo false;fi
if [ $exp ];then echo true;else echo false;fi
will evaluate the operation specified by $op
against the file specified by $file
. As long as there aren't any IFS characters in the expansions of $op
and $file
, and <space> is included in IFS (so field splitting will separate $op and $file into separate arguments to test
) this should do what you want.
Example 3:
If a filename contains any IFS characters, the code in Example 2 won't work, but the commands:
if test "$op" "$file";then echo true;else echo false;fi
if [ "$op" "$file" ];then echo true;else echo false;fi
will do what you want for any valid test
op code.
Example 4:
The commands:
if [[ $op $file ]];then echo true;else echo false;fi
if [[ "$op" $file ]];then echo true;else echo false;fi
if [[ $op "$file" ]];then echo true;else echo false;fi
if [[ "$op" "$file" ]];then echo true;else echo false;fi
are all equivalent and will always give you a syntax error. Since [[
is a keyword (not the name of a utility), the shell itself recognizes that $op
and $file
are variables and doesn't perform field splitting or pathname expansion. Neither ksh
nor bash
accept a variable as an operator in the expression evaluated by [[ expression ]]
and two variables can't be concatenated without an operator between them. So, you get a syntax error.
Example 5:
Since [[
doesn't do field splitting, the commands:
if [[ $exp ]];then echo true;else echo false;fi
if [[ "$exp" ]];then echo true;else echo false;fi
are treated as equivalent to:
if [[ -n "$exp" ]];then echo true;else echo false;fi
as in Example 1 above.
With sea's suggestion of using set -x
(either using that as the 2nd line in your script, or by invoking your script with):
ksh -x script_name operator pathname
you'll be able to see how ksh
handles each of these examples.