Skip to content

/errors/grep/unmatched-paren

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

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:

bash
printf 'call foo(1)\n' > app.log
grep -E 'foo(' app.log

Output · exit 2

grep: Unmatched ( or \(

Basic regex, escaped parenthesis (often written by people who expect the backslash to make it literal):

bash
printf 'call foo(1)\n' > app.log
grep 'foo\(' app.log

Output · exit 2

grep: Unmatched ( or \(

Fix: match the parenthesis literally

bash
printf 'call foo(1)\n' > app.log
grep -F 'foo(' app.log
grep -E 'foo\(' app.log
grep 'foo(' app.log

Output

call foo(1)
call foo(1)
call foo(1)
SyntaxLiteral (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).

bash
printf 'call foo(1)\n' > app.log
grep 'foo\)' app.log

Output · exit 2

grep: Unmatched ) or \)

Patterns from variables

When the pattern comes from input, treat it as data, not as a regex:

bash
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.

Sources