What’s the meaning of the parameter -e for bash shell command line?

The -e option means “if any pipeline ever ends with a non-zero (‘error’) exit status, terminate the script immediately”. Since grep returns an exit status of 1 when it doesn’t find any match, it can cause -e to terminate the script even when there wasn’t a real “error”.

If you want to keep the -e option, but also have a grep command that might validly find no matches, you can append || : to the grep command. This means “or, if the grep command returns a non-zero exit status, run : (which does nothing)”; so the net effect is to disable -e for the grep command. So:

grep PATTERN FILE... || :

Edited to add: The above approach discards every error: if grep returns 1 because it found no matches, that’s ignored, but also if grep returns 2 because there was an error, that’s ignored, and if grep isn’t in the path (so Bash returns 127), that’s ignored — and so on. So, rather than :, it’s probably better to use a command that checks the result code and re-issues the error if it’s something other than 1. For example:

grep PATTERN FILE || (( $? == 1 ))

But this destroys the exit status; usually, when a failed command terminates a Bash script with -e, the script will return the command’s exit-status, but in the above example, the script will just return 1. If (and only if) we care about that, we can fix it by write something like this:

grep PATTERN FILE || exit_code=$?
if (( exit_code > 1 )) ; then
    exit $exit_code
fi

(first line c/o dsummersl‘s comment).

At this point, it’s probably best to create a shell function to handle this for us:

function grep_no_match_ok () {
    local exit_code
    grep "$@" || exit_code=$?
    return $(( exit_code == 1 ? 0 : exit_code ))
}

(note the use of return rather than exit; we’ll let -e handle the exiting when appropriate); this way, we can just write:

grep_no_match_ok PATTERN FILE     # won't kill script if no matches are found

In fact, since we most likely want to use this function for all occurrences of grep in this script, we can actually just name the function grep:

function grep () {
    local exit_code
    command grep "$@" || exit_code=$?
    return $(( exit_code == 1 ? 0 : exit_code ))
}

grep PATTERN FILE     # won't kill script if no matches are found

(note the use of command to bypass the shell function within its own body: we want the function to call the regular program grep, rather than to recurse infinitely).

Leave a Comment