#600

grep rejects common GNU options (-I, -H, -s, -nA1, --include GLOB) and exits 1 on an invalid option

Openasafyishopened 14d ago

just-bash version

3.6.0

Reproduction

cd /w
grep -rIl alpha . 2>/dev/null; echo "rc=$?"
grep -nA1 alpha a.txt; echo "rc=$?"
grep -r --include '*.txt' alpha .; echo "rc=$?"

How you run it

import { Bash } from "just-bash";

const bash = new Bash({ files: { "/w/a.txt": "alpha\ngamma\n" } });
const result = await bash.exec(script);

Expected behavior

GNU grep:

./a.txt
rc=0
1:alpha
2-gamma
rc=0
./a.txt:alpha
rc=0

An option that grep doesn't support should exit with 2. grep uses 1 for "no lines selected" and 2 for errors.

Actual behavior

rc=1
grep: invalid option -- 'A'
rc=1
grep: unrecognized option '--include'
rc=1

The first command fails silently because of 2>/dev/null, and its exit status of 1 looks exactly like "no match".

These GNU forms fail the same way:

  • -I, -H/--with-filename, -s/--no-messages, -a, -Z/--null, --line-buffered, --color[=WHEN], --binary-files=TYPE
  • a value option bundled after other flags: -nA1, -iC2, -rnB3 (-A1 alone works)
  • -e with its value attached or bundled: -ePAT, -rne PAT
  • --include GLOB / --exclude GLOB as two arguments (--include=GLOB works)
  • --context=N, --after-context=N, --before-context=N, --regexp=PAT

Some context: we use just-bash as the shell for an LLM agent. In one eval run, 14 of the agent's 102 recursive greps used -I (-RIl, -RIn, -RInE), and all 14 failed. Four of them redirected stderr, so they just came back empty; one of those was an inventory of HTTP callouts.

Parsing options the way getopt does, plus exit 2 on a usage error, would cover all of this. I looked at main (9ab0e0d): the option loop in src/commands/grep/grep.ts hasn't changed here, and unknownOption in help.ts returns 1 for every command.

Environment

  • Runtime (Node, Bun, browser, CLI): Node
  • Runtime version: 26.8.2
  • Operating system: macOS 15
  • Bundler or framework, when relevant: none

Activity

0

No activity yet.