why [] test makes this script to fail?

Please consider these two scripts:

run.sh:

#!/bin/bash
set -euo pipefail
. "$(dirname $(realpath $BASH_SOURCE))"/init-sudo-script.sh

init-sudo-script.sh

[ ${#BASH_SOURCE[@]} -eq 1 ]
    && echo "must be sourced by another script."
    && exit 10

[ $EUID -ne 0 ]
    && echo "must be executed as root."
    && exit 20

This is correct and it is what I expect to happen:

$ ./run.sh
must be executed as root.
$ echo $?
20

But this I can’t understand:

$ sudo ./run.sh
$ echo $?
1

I know the problem is [ $EUID -ne 0 ] because the script works when I remove it.

I also understand set -e makes the script to exit on any error.

What I don’t understand is why the first guard condition ([ ${#BASH_SOURCE[@]} -eq 1 ]) doesn’t exit with 1 when it fails but the second does.

Does anybody understand what is happening here?

===UPDATE===

I found a way to make it works as I expect:

if [ $EUID -ne 0 ]; then
    echo "must be executed as root."
    && exit 20
fi

I would leave this behind but I’m investing on getting better in Bash. So if anyone can clarify what’s going on I’d appreciate to hear.

Asked By: Saulo

||

I also understand set -e makes the script to exit on any error.

Not "on any error". There are exceptions, one of them is:

The shell does not exit if the command that fails is […] part of any command executed in a && or || list except the command following the final && or ||, […]

(source)

If [ ${#BASH_SOURCE[@]} -eq 1 ] fails then the shell will not exit because of set -e.

Similarly if [ $EUID -ne 0 ] fails then the shell will not exit because of set -e. But it will exit just after because the script ends, i.e. because there is nothing more to execute. And then the exit status of the script will be the exit status of the last command executed; and it happens to be the failing [. This is why you get 1.

Place : (a no-op command that always succeeds) at the end of init-sudo-script.sh and re-run your tests. sudo ./run.sh will return 0 because the last command will be :.


Your updated code with if is different because the exit status from if is:

[…] zero if no condition tested true.

(source)

Answered By: Kamil Maciorowski
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.