tags:

views:

818

answers:

2

Can someone please explain why this command returns an error (on Solaris ksh):

if [ "(" = "(" ]; then echo 1;fi;
ksh: test: argument expected

The same using bash is OK, and echoes "1" as expected
Also, using [[ ]] is OK.

The problem seems to be the first "("

+1  A: 

That command seems to work on my ksh.

However, IIRC in ksh it's recommended to use [[ ]] instead of [ ]. So for a portable solution, I suggest you write it as:

if [[ "(" = "(" ]]; then echo 1; fi;

Do note however that [[]] is subtly different from [] in that wildcard expansions are not done. See http://www.bolthole.com/solaris/ksh-builtins.html#test

Update

For better portability to different shells, I tend to use the built-in test command which in ksh should have the exact same effect as [[]].

if test "(" = "("; then echo 1; fi
lsc
I usually try not to use [[ ]], because it's NOT portable (to bash, anyway)
Joe Watkins
bash supports [[ ]]
anon
oops, my mistake. not to sh anyway
Joe Watkins
Note, I get the same error using test
Joe Watkins
A: 

Does it work if you change the double quotes to single quotes -- i.e.,

if [ '(' = '(' ]; then echo 1;fi;

EDITED TO ADD: I've just been able to recreate the problem with a Digital UNIX ksh. Single quotes don't work either on this platform, however escaping the brackets does work:

if [ '\(' = '\(' ]; then echo 1;fi;

According to the man page for ksh, it states:

The following characters have a special meaning to the shell and cause termination of a word unless quoted:

   ; & ( ) | ^ < > <newline> <space> <tab>

...and goes on to define more parsing rules. It seems that the ( is being interpreted as a special character even when quoted (oddly), hence the requirement for escaping. If you type "set -x" at the command line before you try your if, you'll see exactly what the shell is trying to do sent to stderr preceded with a '+' sign, which may help the tracing; e.g.:

$ set -x
$ if [ '(' = '(' ]; then echo 1;fi;
+ [ ( = ( ]
ksh: test: argument expected
$
$ if [ '\(' = '\(' ]; then echo 1;fi;
+ [ \( = \( ]
+ echo 1
1
$

It may be that it depends on the ksh implementation as well -- e.g., ksh-88 vs ksh-93 and later. On Digital UNIX, the implementation is ksh-88.

Chris J
thanks - at least I'm not going mad, and someone else sees the problem. I can't escape it because the actual code used is in a file read loop, and a variable is used. i.e. if [ "$var" = "test" ]
Joe Watkins
Joe -- I've just tried doing this: [ '\'"$var" = '\(' ] ... which seems to work. If I remove the '\' that precedes "$var" it falls over as expected. Now I don't know what the contents of $var is in you instance, but you might be able to come up with a solution based on this?
Chris J
OK, thanks - contents of var is "(", hence the problem. I'm just going to go for the [[ ]] solution - probably less confusing for future maintainers.
Joe Watkins

related questions