Three grep outcomes: 0: selected lines, 1: no selected lines, 2: search error

GNU grep Exit Status 1 Is Not a Read Error: Handle All Three Outcomes

Distinguish a GNU grep match, no match and search error in Bash, and avoid hiding unreadable inputs behind quiet mode or a generic success message.

GNU grep normally returns zero when it selects a line, one when it selects no lines, and two when an error occurs. A script that treats every nonzero result as a missing keyword can silently turn a failed search into an apparently clean report. Capture and classify the exit status before printing another message or starting another command.

Separate the question from the command’s health

Suppose an administrator searches a saved application log for the literal text ERROR. Finding no selected lines answers a limited question about that input and pattern. It does not establish that the application is healthy. A missing log file answers neither question: the search could not inspect that input successfully.

These distinctions matter in scheduled reports. A message such as ‘No errors found’ is misleading when the report actually failed to open its source. Keep diagnostic messages available and make the wrapper return a failure status when the search itself fails.

Use a Bash wrapper with three explicit branches

The following example searches one file without modifying it. Save the code as check-log.sh and run it with Bash, passing the log path as its single argument. The wrapper prints matching lines and returns grep’s classified outcome rather than disguising it with a later successful printf.

#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
    printf 'Usage: bash check-log.sh LOGFILE\n' >&2
    exit 2
fi
if grep -F -- 'ERROR' "$1"; then
    status=0
else
    status=$?
fi
case "$status" in
    0) printf 'At least one line selected.\n' ;;
    1) printf 'No lines selected for this pattern.\n' ;;
    *) printf 'Search failed; inspect the diagnostic above.\n' >&2 ;;
esac
exit "$status"

The fixed-string flag makes ERROR literal rather than a regular expression. The double dash ends option parsing, and quoting the filename preserves spaces in the supplied argument. The conditional captures the unsuccessful command’s status immediately in the else branch. Do not insert an echo, a date command or another diagnostic before assigning status.

This example does not use a pipeline, so its status belongs directly to grep. If you later add a producer or a formatting pipeline, revisit how each command’s failure is detected. A successful formatter does not prove that an earlier reader succeeded.

Check three disposable inputs before scheduling the wrapper

Use a temporary directory, not a production log, to exercise the wrapper. Create one small text file containing an ERROR line and another containing only an ordinary startup line. Invoke the wrapper on each, then on a filename that does not exist. Inspect the wrapper’s exit status immediately after each run.

The expected classifications are zero for the matching fixture, one for the nonmatching fixture and two for the nonexistent input under GNU grep. A path that is absent remains a useful deterministic error case when your test account has privileges that would otherwise bypass ordinary file permissions. Remove only the temporary files you created after inspecting the results.

A nonzero exit status of one may be an expected search outcome, but your scheduler can still label it a failed job. Decide what your reporting contract should be. If a reporting system intentionally translates a completed no-match search into job success, do so explicitly after preserving the distinct search result; never apply the same translation to read errors.

Do not use quiet mode as a full-input validation check

GNU grep’s quiet mode exits as soon as it finds a match. Its manual explicitly warns that a selected line can produce exit status zero even if an error occurred. For example, when several files are supplied, finding a match is not proof that every input was read successfully.

If the task requires both finding a pattern and detecting input errors across the search, use ordinary grep and redirect standard output to /dev/null when selected text is not needed. Keep standard error visible and classify the result. Avoid the separate suppress-messages option during troubleshooting: hiding a diagnostic does not fix the file access problem.

For time-bounded jobs, the related tutorial on GNU timeout and exit status 124 covers another status layer. A timeout wrapper can return its own outcome, so do not automatically interpret that number as a grep search result.

Review the result before drawing an operational conclusion

  • Confirm that the intended file and time range were searched.
  • Keep the exact pattern and case-sensitivity choice in the report.
  • Distinguish selected lines from individual occurrence counts.
  • Preserve missing-file and access diagnostics.
  • Check the wrapper’s final exit code, not only its final message.

FAQ: Is no output always no match? No. Quiet mode, redirected output and errors can all leave standard output empty. Does one match prove the entire log was checked? Not with early-exit options, and not as a general statement about files outside the search scope.

Source and safety

The GNU grep manual documents normal exit statuses, literal-pattern matching and the quiet-mode exception. This tutorial is for educational purposes. Test the wrapper with disposable fixtures before production use. Searching is read-only, but reports can expose sensitive log text; share only authorised excerpts. The site owner is not responsible for misuse, damage, data loss or production issues.

Leave a Reply

Your email address will not be published. Required fields are marked *