29

This script does not echo "after":

#!/bin/bash -e

echo "before"

echo "anything" | grep e # it would if I searched for 'y' instead

echo "after"
exit

It also would if I removed the -e option on the shebang line, but I wish to keep it so my script stops if there is an error. I do not consider grep finding no match as an error. How may I prevent it from exiting so abruptely?

  • This is an observation meant only for consideration. Perhaps the logic of this script should be thought through again. If it is not important to find the string, why search for it? grep's definition is such that one makes decisions based upon a string's presence or absence. If you don't care either way, then it isn't important. Also, it would seem -e presupposes you do care: so much so that any problem is catastrophic. – Andrew Falanga Dec 15 '16 at 19:38
  • 2
    @AndrewFalanga I do care either way since I am actually analysing the content of var=$(complex command | grep complex_pattern) which may be null (in which case my program should not terminate). This is just a boiled down script which makes the problem occur. No metaphysical blackhole in the logic here, right? ;) – iago-lito Jan 14 '17 at 14:42
  • Knowing now that you intended to capture the output does clarify some things. As presented, it was confusing to me. – Andrew Falanga Jan 14 '17 at 15:19
30
echo "anything" | grep e || true

Explanation:

$ echo "anything" | grep e
### error
$ echo $?
1
$ echo "anything" | grep e || true
### no error
$ echo $?
0
### DopeGhoti's "no-op" version
### (Potentially avoids spawning a process, if `true` is not a builtin):
$ echo "anything" | grep e || :
### no error
$ echo $?
0

The "||" means "or". If the first part of the command "fails" (meaning "grep e" returns a non-zero exit code) then the part after the "||" is executed, succeeds and returns zero as the exit code (true always returns zero).

  • 3
    A slightly shorter version of the same that doesn't spin up /bin/true is: command || : (so in your case, set -e; grep 'needle' haystack || :). – DopeGhoti Dec 15 '16 at 16:45
  • 1
    @DopeGhoti, true is a built-in in some shells (at least on bash 4.3 on RHEL) – iruvar Dec 15 '16 at 16:57
  • 2
    Not valid because if first command fails it will hide the error. A correct solution should return non zero if the first command in the pipe fails. – sorin Jan 17 at 17:47
8

A robust way to safely and optionally grep messages:

echo something | grep e || [[ $? == 1 ]] ## print 'something', $? is 0
echo something | grep x || [[ $? == 1 ]] ## no output, $? is 0
echo something | grep --wrong-arg e || [[ $? == 1 ]] ## stderr output, $? is 1

According to posix manual, exit code 1 means no lines selected, and >1 means an error.

  • 1
    This should be the accepted answer, since it only suppresses the warning exit code (1) if grep does not find anything, yet it passes on true errors (exit codes > 1). The other solutions here always suppress true errors, which is usually bad. – HaroldFinch Aug 29 at 21:26
7

Another option is to add another command to the pipeline - one that does not fail:

echo "anything" | grep e | cat

Because cat is now the last command in the pipeline, it's the exit status of cat, not of grep, that will be used to determine if the pipeline failed or not.

4

Another option:

...
set +e
echo "anything" | grep e
set -e
...
3

Solution

#!/bin/bash -e

echo "before"

echo "anything" | grep e || : # it would if I searched for 'y' instead

echo "after"
exit

Explanation

set -e or set -o errexit

Exit immediately if a pipeline (which may consist of a single simple command), a list, or a compound command (see SHELL GRAMMAR above), exits with a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test following the if or elif reserved words, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted with !. If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit. A trap on ERR, if set, is executed before the shell exits. This option applies to the shell environment and each sub‐ shell environment separately (see COMMAND EXECUTION ENVIRONMENT above), and may cause subshells to exit before executing all the commands in the subshell.

Plus, : is the no-effect command in Bash.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.