How do you cause a script to exit early if there is a syntax issue inside `if [ ]`?

Viewed 94

This will cause the script to halt as expected, because grep a b returns a non-zero exit code and the -e option is set:

#!/bin/bash
set -e
grep a b
echo "hi"
$ ./test.sh
grep: b: No such file or directory

However, this doesn't, even though there is a syntax error:

#!/bin/bash

set -e

if [ $a = 'a' ]; then
  echo "true"
else
  echo "false"
fi

echo "hi"
$ ./test.sh
./test.sh: line 5: [: a: binary operator expected
false
hi

Is there a way to halt the script if there is an issue with the syntax passed to if [ ]?

2 Answers

How do you cause a script to exit early if there is a syntax issue inside if [ ]?

You implement such functionality. Happily it is detectable - test or [ exits with 0 when the expression is true, 1 when the expression is false, but a different exit status is returned when the arguments could not be parsed by test. See posix test EXIT STATUS for reference.

if [ invalid; then
    echo ok
else
   ret=$?
   if ((ret == 1)); then
       echo "It was false"
   else
       echo "Och nuuu - invalid" 
       exit
   fi
fi
   

or you could write your own function wrapper:

# Fun fact: yes `[` is allowed in function names.
# Many other characters are allowed too.
safe[() {
  local ret
  ret=0
  [ "$@" || ret=$?
  if ((ret == 0 || ret == 1)); then
       return "$ret"
  else
       exit 1
  fi
}
if safe[ some expression to check ]; then
     echo 'it is true!'
else
     echo 'it is false!'
fi

You can handle this case using compound commands.

Here is your script using that :

#!/bin/bash

set -e

[ $a = "a" ] && echo "true" || { [ $? != 2 ] && echo "false" || false; }

echo "hi"

If there's a wrong syntax when evaluating the initial [] expression, the return value will be 2 and not 1. With that, you can check when [] fails for syntax reason and force the script to halt with false under set -e. If the syntax is right, it is then a classic if/then/else in the ternary form.

Related