Contents

09/27/2026

grep exit status: 0, 1 and 2 explained

grep exits 0 when it selected at least one line, 1 when it selected none, and 2 when something went wrong, such as a missing file or an invalid pattern. One exception: with -q, a match exits 0 even if another file couldn't be read.

Exit status Meaning
0 At least one line selected (with -v, at least one line that didn't match)
1 No lines selected. Not an error
2 An error: unreadable file, bad regex, bad option

POSIX grep's exit status section defines 0 and 1 and says only that errors are greater than 1. GNU grep uses 2, and its --help sums it up in one line: "Exit status is 0 if any line is selected, 1 otherwise; if any error occurs and -q is not given, the exit status is 2."

Checking it

grep -q FAILED out.txt;  echo $?    # 0 if out.txt contains FAILED
grep -q NOPE out.txt;    echo $?    # 1
grep -q x missing.txt;   echo $?    # 2, with an error on stderr

I ran each line in this post with GNU grep in Git Bash and got the statuses shown.

Three traps

1 is not an error, but set -e treats it as one

Under set -e, a grep that finds nothing stops the script. If no match is fine but a real error isn't, allow exactly 1:

grep pattern file.txt || [ $? -eq 1 ]

That passes on 0 or 1 and still fails when grep exits 2. grep -c is caught the same way: it prints 0 and exits 1.

In a pipeline you get grep's status, not the command before it

./run-tests | grep FAILED reports grep's status. That's how a red build can pass, as in grep exits zero when it finds the word FAILED. With set -o pipefail, the pipeline returns the last non-zero status in it. Bash has it, and POSIX added it in the 2024 edition (POSIX Pipelines). In bash, ${PIPESTATUS[0]} holds the first command's status too.

-q hides an error once something matched

grep -q FAILED a.txt missing.txt exits 0 when a.txt matches, even though missing.txt couldn't be read. Drop -q when you need to know every file was searched.

How to verify

Run your command, then echo $? straight away, before anything else overwrites it. In a script, test the status directly:

if grep -q FAILED out.txt; then
  echo "tests failed"
  exit 1
fi

Questions this raises

Why does grep return exit code 1?

It selected no lines. That's a normal result, not an error; errors are 2 in GNU grep.

Does grep -c return 0 when the count is zero?

No. It prints 0 and exits 1, because no lines were selected. Scripts running under set -e stop there.

How do I get the exit status of the command before grep in a pipeline?

Use set -o pipefail so the pipeline fails when any command in it fails, or read ${PIPESTATUS[0]} in bash right after the pipeline.

What does grep exit status 2 mean?

An error: a file that couldn't be read, an invalid regular expression or a bad option. With -q, a match elsewhere still turns it into 0.