Skip to content

grep -c prints nothing on an invalid pattern, so the #922 idiom answers "present" for a question it never asked #929

Description

@OffgridwithJD

#922 replaced roughly 28 ... | grep -q PAT tests with [ "$(grep -c PAT ... || true)" != 0 ], which fixed a real EPIPE race (#486). The replacement answers present where the original answered absent when grep produces no stdout, and a broken pattern is the way to get there.

Measured

                             new idiom   old idiom
pattern present, valid ERE   present     present
pattern absent,  valid ERE   absent      absent
INVALID ERE (grep rc=2)      present     absent     <- inverted

The mechanism is that grep -c prints nothing on a usage error, not 0:

grep -cE '[' file  ->  stdout is []   (empty)
[ "" != 0 ]        ->  TRUE           (string comparison: "" is not "0")

So the helper reports the pattern PRESENT for a question it never managed to ask.

Why it is worth a line, even though nothing is broken today

Every pattern in the tree is valid right now, so no site is wrong. The hazard is the direction of the next edit. A premise arm phrased to want present — and most of them are, because a premise asserts the fixture really is in the state the test needs — turns GREEN when its pattern stops compiling. The arm passes because the instrument broke, which is the failure this repository spends most of its effort refusing elsewhere.

The old form failed the other way: a broken pattern reported absent and the arm went red, which is loud.

What I did not find

I could not make an unreadable file produce the inversion: grep -c on a file it cannot read still prints 0, so that case answers absent and agrees with the old form. (My first attempt at that test was invalid anyway — I ran it as root, which bypasses the mode bits.) So the reachable trigger is a pattern that does not compile, not an I/O failure.

Suggested shape of a fix

Make the empty case loud rather than truthy. Either compare numerically, so an empty value is a hard error instead of a silent present:

[ "$(grep -c PAT ... || true)" -gt 0 ]      # "integer expression expected" on empty

or default it explicitly:

_n="$(grep -c PAT ... || true)"; [ "${_n:-0}" != 0 ]

The second keeps the current semantics and makes the intent visible; the first turns a broken pattern into a failure, which matches how the rest of the harness treats an instrument that could not run.

Found while reviewing the #486 sweep for #926. Reported independently by @linuxhikerpm, whose version also named unreadable input — that half does not reproduce, per above.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions