Prevent grep returning an error when input doesn't match

Sure:

ps -ef | grep bar | { grep -v grep || true; }

Or even:

ps -ef | grep bar | grep -v grep | cat

Short answer

Write

ps -ef | grep bar | { grep -v grep || test $? = 1; }

if you are using set -e.

If you use bash's pipefail option (set -o pipefail), remember to apply the exception handling (||test) to every grep in the pipeline:

ps -ef | { grep bar || test $? = 1; } | { grep -v grep || test $? = 1; }

In shell scripts I suggest you to use the ”catch-1-grep“ (c1grep) utility function:

c1grep() { grep "$@" || test $? = 1; }

Explained

grep's exit status is either 0, 1 or 2: [1]

  • 0 means a line is selected
  • 1 means no lines were selected
  • 2 means an error occurred

grep can also return other codes if it's interrupted by a signal (e.g. 130 for SIGINT).

Since we only want to ignore exit status 1, we use test to suppress that specific exit status.

  • If grep returns 0, test is not run.
  • If grep returns 1, test is run and returns 0.
  • If grep returns any other value, test is run and returns 1.

In the last case, the script will exit immediately due to set -e or set -o pipefail. However, if you don't care about grep errors at all, you can of course write

ps -ef | grep bar | { grep -v grep || true; }

as suggested by Sean.


[additional] usage in shell scripts

In shell scripts, if you are using grep a lot, I suggest you to define an utility function:

# "catch exit status 1" grep wrapper
c1grep() { grep "$@" || test $? = 1; }

This way your pipe will get short & simple again, without losing the features of set -e and set -o pipefail:

ps -ef | c1grep bar | c1grep -v grep

FYI:

  • I called it c1grep to emphasize it's simply catching exit status 1, nothing else.
  • I could have called the function grep instead (grep() { env grep "$@" ...; }), but I prefer a less confusing and more explicit name, c1grep.

[additional] ps + grep

So if you want to know how to avoid grep -v grep or even the | grep part of ps|grep at all, take a look at some of the other answers; but this is somewhat off-topic imho.


[1] grep manpage


A good trick to avoid grep -v grep is this:

ps -ef | grep '[b]ar'

That regular expression only matches the string "bar". However in the ps output, the string "bar" does not appear with the grep process.


In the days before I learned about pgrep, I wrote this function to automate the above command:

psg () { 
    local -a patterns=()
    (( $# == 0 )) && set -- $USER
    for arg do
        patterns+=("-e" "[${arg:0:1}]${arg:1}")
    done
    ps -ef | grep "${patterns[@]}"
}

Then,

psg foo bar

turns into

ps -ef | grep -e '[f]oo' -e '[b]ar'

Tags:

Bash

Grep