user3663882 user3663882 - 2 months ago 6
Linux Question

Bash scripting check condition

I'm new to bash scripting and trying to write the following simple

function wait_some {
if [ -z $1 ];
echo some_string
then if ! [[ $1 =~ ^[0-9]+([.][0-9]+)?$ ]];
then
echo "$1 is not a number"
exit 2
else echo "it's a number"
fi
fi
}

wait_some 2.2 //prints some_string and then it's a number


And this works as expected.

But if I delete echo "some string' it prints nothing:

function wait_some {
if [ -z $1 ];
then if ! [[ $1 =~ ^[0-9]+([.][0-9]+)?$ ]];
then
echo "$1 is not a number"
exit 2
else echo "it's a number"
fi
fi
}

wait_some 2.2 //prints nothing


Why? Why does deleting
echo some_string
right after the condition checking breaks the function?

Answer

It is because the if-condition is executed as a compound statement in bash i.e. command1;command2 and also incorrect usage of -z in the test operator.

I will explain it with the debugging I did with the set -x option for both the examples.

For the successful, this is what the execution sequence is

++ wait_some 2.2
++ '[' -z 2.2 ']'
++ echo some_string
some_string

As you can see the two-conditions getting executed [ -z 2.2 ] is failing. But why? Because the string has a non-zero length (See how -z works) and the check is yielding a failure of the condition, which should have been [ ! -z 2.2 ]. And it does not end at that.

Because of the combined set of commands you have used, command1;command2 the command1 the failing if-condition, now command2 which is just a plain echo runs successfully with a positive return code making the overall if-condition successful, leading to the regex search and you are able to see the subsequent echo'ed statement.

Now for the failure case, the expanded result from set -x looks like

++ wait_some 2.2
++ '[' -z 2.2 ']'

As you can see, on removing the echo statement, the overall return code for the if-condition has become false and the inner conditions are not exercised at all. Also removing the echo statement is similar to actually adding a false operator in the script like

if [ -z $1 ];
    false

which would have expanded into

++ wait_some 2.2
++ '[' -z 2.2 ']'
++ false

leading to the failure of your condition. The ideal way your script should have been coded is something like

#/bin/bash

# See the updated if-condition and code reorganization

function wait_some { 
    if [ ! -z "$1" ];                            
    then
       if ! [[ $1 =~ ^[0-9]+([.][0-9]+)?$ ]];
        then
            echo "$1 is not a number"
            exit 2
        else echo "it's a number"
        fi
    fi
}

wait_some 2.2

The best thing about your error is even http://www.shellcheck.net/ couldn't identify the incorrect syntax in the if-condition and asserted the script didn't have any issues.

Comments