Skip to content

/errors/grep/unmatched-bracket

grep: Unmatched [, [^, [:, [., or [=

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · grep (GNU grep) 3.0updated
tool
grep
exit code
2
versions
GNU grep 3.x
os
linux, macos, windows

GNU grep reports grep: Unmatched [, [^, [:, [., or [= when the pattern contains an opening [ with no closing ]. In a regular expression [ starts a bracket expression such as [a-z], so grep '[ERROR' is an invalid regex and grep exits with status 2. To search for the bracket itself, use grep -F (fixed string) or escape it as \[.

Reproduce it

bash
printf '[ERROR] disk full\n[INFO] ok\n' > app.log
grep '[ERROR' app.log

Output · exit 2

grep: Unmatched [, [^, [:, [., or [=

Fix: search for a fixed string

bash
printf '[ERROR] disk full\n[INFO] ok\n' > app.log
grep -F '[ERROR' app.log
grep '\[ERROR' app.log
grep -c '^\[[A-Z]*\]' app.log

Output

[ERROR] disk full
[ERROR] disk full
2

-F turns off regex interpretation entirely. \[ escapes only the bracket. Keep the pattern in single quotes, so the shell passes the backslash to grep unchanged.

The same problem with parentheses

With grep -E (extended regex), ( opens a group, and a lone one fails in the same way:

bash
echo 'f(x)' | grep -E 'f('

Output · exit 2

grep: Unmatched ( or \(

Use grep -F 'f(' or grep -E 'f\('. In basic regex (plain grep) ( is literal and \( starts a group, the opposite of -E.

Sources