ss1
ss1

Reputation: 1191

Bash script doesn't continue when condition fulfilled

To check the validity of lines in a file I'm using a condition which is met when egrep -v does NOT return an empty result. When there are invalid lines, then this works fine (i.e. the conditional block is executed), but when every line is valid then the script ends without further processing.

Script:

INVALID_HOSTS=$(egrep -v ${IP_REGEX} hosts)
if [[ ! -z "${INVALID_HOSTS}" ]]; then
    echo "Invalid hosts:"
    for entry in ${INVALID_HOSTS}
        do echo ${entry}
    done
    exit_with_error_msg "hosts file contains invalid hosts (Pattern must be: \"\d+.\d+.\d+.\d+:\d+\"), exiting"
else
    echo "all cool"
fi
echo "after if-else"

So when there are no invalid lines then neither the echo "all cool" nor echo "after if-else" get executed. The script just stops and returns to the shell.

When set -x is enabled, then it prints:

++ egrep -v '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):([1-9]|[1-5]?[0-9]{2,4}|6[1-4][0-9]{3}|65[1-4][0-9]{2}|655[1-2][0-9]|6553[1-5])$' hosts
+ INVALID_HOSTS=

Playing around with it I'm sure that it's about the if [[ ! -z "${INVALID_HOSTS}" ]]; then, but my bash wizardry is not strong enough to overcome this magical barrier.

Thanks for any help!

Upvotes: 1

Views: 801

Answers (1)

Ondrej K.
Ondrej K.

Reputation: 9664

This is a bit long for a comment. I'll start it as an answer and we can work our way through further details or I can scrap it entirely if not helpful. I'll make some assumptions and let us see if it hits the spot.

For starters, you do indeed use the value further, so command expansion into a variable is not entirely useless, but otherwise it's much easier to determine match (or lack thereof) of grep through it's return value. If anything matched (output would be non-empty), it returns (shell true) value of 0, otherwise it returns false (in this case 1). Not to mention the ! -z test notation should really be -n if used at all.

And this is where I'd start assuming a bit. I suspect this is not your entire script and you have errexit option turned on in that shell session (or through rc file in general). Either by means of set -o errexit or set -e or running bash with -e option. Since grep not matching anything returns as failed, your shell (script execution) would terminate after having encountered a failing command.

Observe the difference between:

$ bash -ec 'grep "BOGUS" /etc/fstab  ; echo "$?"'
$ bash -c 'grep "BOGUS" /etc/fstab  ; echo "$?"'
1

With errexit, bash terminates after grep has "failed" and we never even reach the echo.


Since the assumption has proven to be correct, small extension. If errexit is what you want, you'd need to either change the option value before/after a command you want to be able to fail (return non-zero value) without affecting your script:

set +o errexit
grep THIS_COULD_NOT_MATCH...
set -o errexit

Or you can ignore return value of individual commands by ensuring their success:

grep THIS_COULD_NOT_MATCH... || true

You can also still use potentially "failing" commands safely in conditionals (such as if) without terminating your shell.

Upvotes: 2

Related Questions