Skip to content
Latchkey

Fail a CI Step When grep Finds a Pattern

A bare grep exits 0 when it finds a match, so it naturally fails a step when a forbidden pattern is present.

The most common grep job in CI is a gate: fail if something bad appears, or fail if something required is missing. Getting the exit-code logic right is the whole trick.

What it does

grep returns 0 on a match and 1 on no match, so you can build two opposite gates. To fail when a forbidden string appears, invert the logic: if grep finds it (exit 0), make the step exit non-zero. To fail when a required string is absent, let a bare grep fail naturally (exit 1).

Common usage

Terminal
# FAIL if a forbidden pattern is found
if grep -rq "DO_NOT_COMMIT" src/; then
  echo "Forbidden marker found"; exit 1
fi

# FAIL if a required pattern is missing
grep -q "BUILD SUCCESS" build.log

# one-liner: fail on any leftover debugger statement
! grep -rq "binding.pry" src/

Options

IdiomEffect
grep -q XStep fails if X is absent (exit 1)
! grep -q XStep fails if X is present
if grep -q X; then exit 1; fiExplicit fail-on-match with a message
grep -q X || trueNever fail on this grep

In CI

For "no forbidden strings" checks, ! grep -rq PATTERN . is the compact form; it exits 0 when nothing matches and non-zero when the pattern is found. Add --exclude-dir to avoid scanning vendored code. Print a helpful message in the if form so the failure log says what was found.

Common errors in CI

A fail-on-match gate that "never fails" is often using grep X || true, which swallows the result, or relying on grep -v whose exit code is inverted. A required-pattern gate that "always fails" may be running under set -e where an unrelated earlier grep already aborted. Keep each grep gate explicit and test both the present and absent cases.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →