1

I have following in a bash script:

echo "status: [$status] and message: [$message]"
if [ "${status}" -eq 0 && "$message" = "ERROR" ];
then
        echo "Exit 0";
        exit 0
fi

status: [0] message: [ERROR]

However, it gives below error, and the logic under then i.e. exit 0 never gets executed:

line 2: [: missing `]'

It seems to be complaining about the missing closing ], however, it is there. What am i missing here?

AdminBee
  • 22,803

2 Answers2

2

The closing ] is actually not there.

You have:

cmd1 with its args && cmd2 with its args

Which runs cmd2 if and only if cmd1 succeeds.

Where here cmd1 is the [ command and cmd2 is the command whose name is stored in $message.

IOW, the first command is

[ "${status}" -eq 0

Which is missing its closing ] and the second is:

"$message" = "ERROR" ]

You want

if [ "${status}" -eq 0 ] && [ "$message" = "ERROR" ]; then...

In Korn-like shells such as bash, you can also use the [[...]] construct in place of the [ command which understands a sort of micro-language with its very own syntax which as it happens also has a && operator.

if [[ $status -eq 0 && $message = ERROR ]]; then

But beware that contrary to [, that one introduces a command injection vulnerability if the value of $status could be under the control of an attacker.

In bash, ['s -eq operator doesn't have the problem as it only accepts decimal integer numbers and not arbitrary arithmetic expressions like for [[...]]'s -eq.

bash-5.0$ status='a[$(echo>&2 Gotcha)]'
bash-5.0$ [[ $status -eq 0 ]]
Gotcha

This kind of problem also affects the (( status == 0 )) operator to evaluate C-like arithmetic expressions¹ (also from ksh):

bash-5.0$ (( status == 0 ))
Gotcha

¹ there's also a && in those arithmetic expressions, but you can't use it here as ((...)) is only for arithmetic stuff so you can't do string comparison in there, you'd need if (( status == 0 )) && [ "$message" = ERROR ].

1

The problem you are facing is that you are using the [ test construct. This construct does not support boolean operators in the argument in the way the korn-shell/bash-style [[-operator does, therefore only one single test may be stated inside [ ... ].

You can either concatenate the two conditions via the &&-chaining at shell level as separate tests, i.e.

if [ "${status}" -eq 0 ] && [ "$message" = "ERROR" ];

or use the more convenient [[ ... ]]-operator instead

if [[ "${status}" -eq 0 && "$message" = "ERROR" ]];
AdminBee
  • 22,803