me_and
me_and

Reputation: 15634

ksh bad [ … ] syntax not resulting in error

I've just found the following code in a ksh script:

  if [ "${file_id}" = "0" ] || [ "${file_id}" = "100" ] || "${file_id}" = "100" ]
  then
    # Do some stuff
  fi

Note, in particular, the missing [ before the third ${file_id}.

I'm happy that this isn't very pleasant syntax, even without that error, and that [[ … ]] is generally preferable to [ … ] in ksh.

However, this code runs entirely as desired, and ksh -n doesn't object to the above at all. Why doesn't the above fail?

Upvotes: 2

Views: 319

Answers (2)

chanchal1987
chanchal1987

Reputation: 2367

if [ "${file_id}" = "0" ] || [ "${file_id}" = "100" ] || "${file_id}" = "100" ]

This command exicuted from Left to Right. If this command found the value of file_id is 0 then it will not check for the next conditions because, these conditions are separated with the or operator. If both 1st and 2nd conditions will not satisfied then it will try to check for the 3rd condition and it will be failed.

file_id=1000
if [ "${file_id}" = "0" ] || [ "${file_id}" = "100" ] || "${file_id}" = "100" ]
then
echo "Exicuted for file_id=$file_id"
fi


ksh: 1000:  not found.

Upvotes: 2

Dimitre Radoulov
Dimitre Radoulov

Reputation: 28000

My first guess is that this will execute correctly with most (or all) Bourne-type shells as long as the first expression evaluates true. This is expected behavior, as the && and || actually short-circuit the execution: i.e. In a || b, the b part is not evaluated if a is true.

Consider the following:

% for sh in ash bash ksh zsh;do

 printf 'running %s with id %d\n\n' "$sh" 0
 "$sh" -c 'file_id=0;[ "${file_id}" -eq 0 ] || oops'

done
running ash with id 0

running bash with id 0

running ksh with id 0

running zsh with id 0


% for sh in ash bash ksh zsh;do

  printf 'running %s with id %d\n\n' "$sh" 1
 "$sh" -c 'file_id=1;[ "${file_id}" -eq 0 ] || oops'

done
running ash with id 1

ash: oops: not found
running bash with id 1

bash: oops: command not found
running ksh with id 1

ksh: oops: not found
running zsh with id 1

zsh:1: command not found: oops

There is more though, you cannot type whatever you want on the right side of the short-circuiting expression, because the parser will try to parse the entire line, before executing it (i.e. a misplaced metacharacter will cause an error)

% ksh -c 'id=0; [ "$id" -eq 0 ] || )' 
ksh: syntax error: ')' unexpected

Notice also that as long as the command (builtin or external) execution is deferred, the shell couldn't know if it's valid or not. On the contrary, the shell reserved words syntax and the positions of the metacharacters are known in parse-time:

% ksh -c 'type [ [[;id=0; [ "$id" -eq 0 ] || [[ '
ksh: syntax error: unexpected EOF
% ksh -c 'type [ [[;id=0; [ "$id" -eq 0 ] || [ ' 
[ is a shell builtin
[[ is a reserved word

Upvotes: 1

Related Questions