`set -e` and `grep` idiom for preventing premature exit from shell script when pattern not found

5,481

You can put the grep in an if condition, or if you don't care about the exit status, add || true.

Example: grep kills the shell

$ bash
$ set -e
$ echo $$
33913
$ grep foo /etc/motd
$ echo $$
9233

solution 1: throw away the non-zero exit status

$ bash
$ set -e
$ echo $$
34074
$ grep foo /etc/motd || true
$ echo $$
34074

solution 2: explicitly test the exit status

$ if ! grep foo /etc/motd; then echo not found; fi
not found
$ echo $$
34074

From the bash man page discussing set -e:

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 !.

Share:
5,481

Related videos on Youtube

Yeow_Meng
Author by

Yeow_Meng

Juggler and rookie programmer.

Updated on September 18, 2022

Comments

  • Yeow_Meng
    Yeow_Meng almost 2 years

    Help required - in the context of shell scripting on a GNU/LINUX bash:

    I always use set -e. Often, I would like to grep and do not always want the script to terminate execution if grep has an exit status of 1 indicating pattern not found.

    Somethings I have tried to solve this problem are as follows:

    (Try I)
    If set +o pipefail and invoke grep with something like grep 'p' | wc -l then I get the desired behaviour until a future maintainer enables pipefail. Also, I like enabling pipefail so this does not work for me.

    (Try II)
    Use a sed or awk and only print lines matching pattern, then wc matched lines to test for matched pattern. I don't like this option because using sed to grep seems like a workaround for my true problem.

    (Try III)
    This one is my least favorite - something like: set +e; grep 'p'; set-e

    Any insight/idioms would be most appreciated - thank you.

  • schily
    schily over 8 years
    Given that bash for a long time did not implement -e correctly, it may be that the documentation is not yet correct. As the text seems to be identical with the bash-3.x man page, please note: all bash versions before bash4.0 did implement -e incorrectly.
  • schily
    schily over 8 years
    Also note that as the POSIX standard was wrong as well, we changed the POSIX text for error handling with -e in 2009
  • zwol
    zwol over 8 years
    @schily Please give pointers to where one may find out what the 'correct' behavior of -e is, what bash < 4 did differently, and what was changed in POSIX.
  • schily
    schily over 8 years
    The bugs in bash-3 basically make it unusable for make as it did not always exit on errors. For the related POSIX discussions, you may like to check austingroupbugs.net
  • zwol
    zwol over 8 years
    @schily Could you please be more specific?
  • Yeow_Meng
    Yeow_Meng over 8 years
    A Lesson learned: I had a professor who taught sh. He said your scripts will be portable and your understanding of the shell will be pure. A few years later writing Bash in sin, I now understand his insights more clearly. if test -e "$file"; then ... makes it clear that we are manipulating control flow based on the Exit Status of the commands in the if guard.