Andrzej Okrasiński
Andrzej Okrasiński

Reputation: 21

Order of evaluation of bash expression when using vs not using test

Why does the following script gives different outputs, when the same expression is evaluated with and without test? What rules are to be taken into account: operator precedence, left-to-right or right-to-left argument evaluation ...? In my opinion it is important to understand the logic of bash at this basic level.

function a()
{
    local r=1
    printf "a%d" $r
    return $r
}

function b()
{
    local r=1
    printf "b%d" $r
    return $r
}

function c()
{
    local r=1
    printf "c%d" $r
    return $r
}

printf "$BASH_VERSION\n" #outputs 4.3.48(1)-release
a || b && c #outputs a1b1
printf "\n"
test a || b && c #outputs c1
printf "\n"

Upvotes: 2

Views: 278

Answers (2)

Inian
Inian

Reputation: 85580

Your usage of test is incorrect in this context. test sets the return code to the calling shell by evaluating an expression. The way you've used it, test a does not evaluate to an expression but ends up setting a code as test 1 which does a string check and always asserts a code 0 (success error code). See

test 0; echo $?
0
test 1; echo $?
0
test false; echo $?
0
test true; echo $?
0

test evaluates the expression a||b which sets up a return code 1 to test which returns a success error code and runs the function c which prints the value you are seeing.

For cases of simplicity, I've changed the function calls to use command false which returns error code 1 to the shell as your function.

bash -cx "test false || false && echo hi"
+ test false
+ echo hi
hi

As you can see, the moment test false|| false is run, the command sets success code to the shell and with the operand && the echo command is run.

For checking the error code from the function, perhaps you should have checked as

test a != "0" 

See The classic test command

Upvotes: 1

melpomene
melpomene

Reputation: 85767

That's because

a

runs a whereas

test a

runs test, passing a as an argument. They're completely different commands.

Similarly,

pwd

runs pwd, but

echo pwd

runs echo, passing pwd as an argument.


X || Y is not an expression, it's a compound command that first runs the X subcommand and then (if its exit status is non-zero) runs Y.

See https://www.gnu.org/software/bash/manual/bashref.html#Lists for details.

Upvotes: 1

Related Questions