What's the meaning of the parameter -e for bash shell command line?
Solution 1:
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).
Solution 2:
From the fine manual:
In addition to the single-character shell command-line options (see The Set Builtin), there are several multi-character options that you can use.
And then if we look at what set
has to say:
-e
Exit immediately if a pipeline (see Pipelines), which may consist of a single simple command (see Simple Commands), a subshell command enclosed in parentheses (see Command Grouping), or one of the commands executed as part of a command list enclosed by braces (see Command Grouping) returns a non-zero status.
So when you say bash -e
, if any command in the script fails (i.e. returns a non-zero exist status), then the whole script immediately fails. So your grep
is returning a non-zero value because it isn't matching and that's shutting down the whole script if you specify -e
when running bash.