smarber
smarber

Reputation: 5084

Short form of if behaves differently

In my unit test part, I've a script unit_runner.sh which looks for my unit tests files, sources them and runs every test function in them.

unit_test_runner script

Please note that my tests are not supposed to write in the stdout

# ${test} contains the test function name
# So this runs a test, catch the error message if any
error_output=$(${test} 2>&1)
code=$?
# If the executed test does not return 0 or writes into stderr,
# consider it as failure
if [[ ${code} -ne 0 || ! -z ${error_output} ]]
then
     # error
fi

A specific test function In one test function I had:

test_do_something() {
    # the function I want to test

    result=do_something ${input}

    if [[ "${result}" = "fake output" ]]
    then
        exit 55
    fi
}

This worked and this test passed. I wanted to shorten it as follows

 [[ "${result}" = "fake output" ]] && exit 55

This makes my test fail. AFAIK, these two forms as exactly the same in terms of behaviors.

What's wrong?

Upvotes: 1

Views: 58

Answers (1)

Thomas
Thomas

Reputation: 182000

The problem is that the exit code of a function is the exit code of the last statement in that function.

The if statement has an exit code of 0 if its condition was false:

$ if false; then echo false; fi
$ echo $?
0

But if we use the short form, the result is the exit code of the entire expression. Because the part before && evaluates to false (i.e. 1), the second part doesn't get executed, and the result of the first part becomes the exit code of the entire expression:

$ false && echo false
$ echo $?
1

To work around this, you can add an explicit return 0 or exit 0 at the end of your function, but this defeats the purpose of the shorthand notation.


Reference: the bash manpage.

[[ expression ]]

Return a status of 0 or 1 depending on the evaluation of the conditional expression expression.

...

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

The if list is executed. If its exit status is zero, the then list is executed. Otherwise, each elif list is executed in turn, and if its exit status is zero, the corresponding then list is executed and the command completes. Otherwise, the else list is executed, if present. The exit status is the exit status of the last command executed, or zero if no condition tested true.

Upvotes: 3

Related Questions