2

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?

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Note that the -z test isn't even necessary; you can try to match the empty string against the regular expression just fine. An empty string is not a number :)
@chepner : thanks for the comment. Didn't want to modify the author's code except the incorrect syntaxes. A lot of improvements are possible. :)
@chepner : Would like to know from greats like you if the explanation for questions like this are good enough. Would appreciate your suggestions! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.