zjmiller
zjmiller

Reputation: 2807

Question about shell commands and grep

Does anyone know why

grep "p\{2\}" textfile

will find "apple" if it's in the file, but

grep p\{2\} textfile

won't?

I'm new to using a command line and regular expressions, and this is puzzling me.

Upvotes: 3

Views: 283

Answers (5)

nsfyn55
nsfyn55

Reputation: 15363

From the grep man page

In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the backslashed versions \?, \+, \{, \|, \(, and \).

so these two become functional equivalent

egrep p{2} 

and

grep "p\{2\}" 

the first uses EREs(Extended Regular Expressions) the second uses BREs(Basic Regular Expressions) in your example because your using grep(which supports BREs when you don't use the -e switch) and you're enclosed in quotes so "\{" gets expanded as a special BRE character.

You second instance doesn't work because your just looking for the literal string 2{p} which doesn't exist in your file

you can demonstrate that grep is expanding your string as a BRE by trying:

grep "p\{2"

grep will complain

grep: Unmatched \{  

Upvotes: 0

Emiliano Poggi
Emiliano Poggi

Reputation: 24846

The first one greps the pattern using regex, then pp:

echo "apple" | grep 'p\{2\}'

The second one greps the pattern literally, then p{2}:

echo "ap{2}le" | grep p\{2\}

Upvotes: 0

Vikram.exe
Vikram.exe

Reputation: 4585

Although this has already been answered, but since you are new to all this stuff, here is how to debug it:

-- get the pid of current shell (using ps).

 PID TTY          TIME CMD

 1611 pts/0    00:00:00 su

 1619 pts/0    00:00:00 bash

 1763 pts/0    00:00:00 ps

-- from some other shell, attach strace (system call tracer) to the required pid (here 1619):

strace -f -o <output_file> -p 1619

-- Run both the commands that you tried

-- open the output file and look for exec family calls for the required process, here: grep

The output on my machine is some thing like:

1723  execve("/bin/grep", ["grep", "--color=auto", "p{2}", "foo"], [/* 19 vars */]) = 0

1725  execve("/bin/grep", ["grep", "--color=auto", "p\\{2\\}", "foo"], [/* 19 vars */]) = 0

Now you can see the difference how grep was executed in both the cases and can figure out the problem yourself. :)

still the -e flag mystery is yet to be solved....

Upvotes: 2

65Fbef05
65Fbef05

Reputation: 4522

With quotes, your complete regex gets passed directly to grep. Without the quotes, grep sees your regex as p{2}.

Edit:

To clarify, without the quotes your slashes are being removed by shell before your regex is passed to grep.

Try:

echo grep p\{2\} test.txt

And you'll see your output as...

grep p{2} test.txt

The quotes prevent shell from escaping characters before they get to grep. You could also escape your slashes and it will work without quotes - grep p\\{2\\} test.txt

Upvotes: 0

Lars Wiegman
Lars Wiegman

Reputation: 2427

Without the quotes, the shell will try to expanding the options. In your case the curly brackets '{}' have a special meaning in the shell much like the asterisk '*' which expands to a wildcard.

Upvotes: 1

Related Questions