grep: Unmatched ( or \(
- tool
- grep
- exit code
- 2
- versions
- GNU grep 3.x
- os
- linux, macos, windows
grep: Unmatched ( or \( means the pattern opens a regex group that is never closed. The parenthesis that counts as "open group" depends on the syntax: with grep -E it is a bare (, with plain grep (basic regex) it is \(. If you want to find the text foo(, use grep -F 'foo(', which matches fixed strings and parses no regex. grep exits with status 2 and searches nothing.
Reproduce the error
Extended regex, bare parenthesis:
printf 'call foo(1)\n' > app.log
grep -E 'foo(' app.logOutput · exit 2
grep: Unmatched ( or \(
Basic regex, escaped parenthesis (often written by people who expect the backslash to make it literal):
printf 'call foo(1)\n' > app.log
grep 'foo\(' app.logOutput · exit 2
grep: Unmatched ( or \(
Fix: match the parenthesis literally
printf 'call foo(1)\n' > app.log
grep -F 'foo(' app.log
grep -E 'foo\(' app.log
grep 'foo(' app.logOutput
call foo(1) call foo(1) call foo(1)
| Syntax | Literal ( | Group |
|---|---|---|
| grep (basic, BRE) | ( | \( ... \) |
| grep -E (extended, ERE) | \( | ( ... ) |
| grep -F (fixed strings) | ( | no groups |
| grep -P (PCRE) | \( | ( ... ) |
The closing parenthesis
An unbalanced \) in basic regex fails with the sibling message grep: Unmatched ) or \). In extended regex, GNU grep accepts a lone ) as a literal character, so grep -E 'foo)' does not fail; it just searches for foo).
printf 'call foo(1)\n' > app.log
grep 'foo\)' app.logOutput · exit 2
grep: Unmatched ) or \)
Patterns from variables
When the pattern comes from input, treat it as data, not as a regex:
needle='foo(1)'
printf 'call foo(1)\n' | grep -F -- "$needle"Output
call foo(1)
-- stops option parsing, so a value that starts with - is not read as an option.