Skip to content
Advertisement

Script exits with error when var=$(… | grep “value”) is empty, but works when grep has results

I have the following bash code (running on Red Hat) that is exiting when I enable set -o errexit and the variable in the code is empty, BUT works fine when the variable is set; the code is designed to test if a screen session matching .monitor_* exists, and if so do something.

I have the following turned on:

set -o errexit
set -x xtrace; PS4='$LINENO: '

If there is a session matching the above pattern it works; however, if nothing matches it just exits with no information other than the following output from xtrace

someuser:~/scripts/tests> ./if_test.sh
+ ./if_test.sh
+ PS4='$LINENO: '
4: set -o errexit
5: set -o pipefail
6: set -o nounset
88: /usr/bin/ls -lR /var/run/uscreens/S-storage-rsync
88: grep '.monitor_*'
88: awk '{ print $9 }'
88: /usr/bin/grep -Ev 'total|uscreens'
8: ms=

I tested the command I am using to set the ms var and it agrees with the xtrace output, it’s not set.

someuser:~/scripts/tests> test -n "${mn}"
+ test -n ''

I have tried using a select statement and got the same results… I can’t figure it out, anyone able to help? Thanks.

I read through all the possible solution recommendations, nothing seems to address my issue.

The code:

#!/usr/bin/env bash

set -o xtrace; PS4='$LINENO: '
set -o errexit
set -o pipefail
set -o nounset

ms="$(/usr/bin/ls -lR /var/run/uscreens/S-"${USER}" | /usr/bin/grep -Ev "total|uscreens" | grep ".monitor_*" | awk '{ print $9 }')"

if [[ -z "${ms}" ]]; then
    echo "Handling empty result"
elif [[ -n "${ms}" ]]; then
    echo "Handling non-empty result"
fi

The following answer was proposed: Test if a variable is set in bash when using “set -o nounset”; however, it doesn’t address the issue at all. In my case the variable being tested is set and as stated in my detail, it’s set to "", or nothing. Thank you; however, it doesn’t help.

It really seems to be the variable declaration that it isn’t liking.

ms="$(/usr/bin/ls -lR /var/run/uscreens/S-"${USER}" | /usr/bin/grep -Ev "total|uscreens" | grep ".monitor_*" | awk '{ print $9 }')"

Advertisement

Answer

  • You’re running set -o pipefail, so if any component in a pipeline has a nonzero exit status, the entire pipeline is treated as having a nonzero exit status.
  • Your pipeline runs grep. grep has a nonzero status whenever no matches are found.
  • You’re running set -o errexit (aka set -e). With errexit enabled, the script terminates whenever any command fails (subject to a long and complicated set of exceptions; some of these are presented in the exercises section of BashFAQ #105, and others touched on in this excellent reference).

Thus, when you have no matches in your grep command, your script terminates on the command substitution running the pipeline in question.


If you want to exempt a specific command from set -e‘s behavior, the easiest way to do it is to simply append ||: (shorthand for || true), which marks the command as “checked”.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement