Search code examples
regexshellgrepquoting

grep returns "<regular expression>" No such file or directory


I have the following regular expression to match a phone number. The regular expression works (123)123-123, but I am puzzled by the last result.

user@host: grep -l -v -f *.txt -E "(\d{3})-\d{3}-\d{3}"
f2.txt
f3.txt
f4.txt
grep: (\d{3})-\d{3}-\d{3}: No such file or directory

Why is grep searching the regular expression?

Here is the ls:

user@host:/tmp# ls
f1.txt  f2.txt  f3.txt  f4.txt  

Solution

  • The grep usage is

    grep [OPTION]... PATTERN [FILE]...
    

    Your command expands to

    grep -l -v -f f1.txt f2.txt f3.txt f4.txt -E "(\d{3})-\d{3}-\d{3}"
    

    which is equivalent to

    grep -f f1.txt -l -v -E f2.txt f3.txt f4.txt "(\d{3})-\d{3}-\d{3}"
    

    which is "use the file f1.txt as a file containing patterns, and search the files f2.txt, f3.txt, f4.txt and (\d{3})-\d{3}-\d{3}. Apply options -l, -v and -E everywhere."

    Maybe you meant

    grep -l -v -E "(\d{3})-\d{3}-\d{3}" *.txt
    

    instead?

    The relevant part of the man page reads as follows:

    -f FILE, --file=FILE
    Obtain patterns from FILE, one per line. If this option is used multiple times or is combined with the -e (--regexp) option, search for all patterns given. The empty file contains zero patterns, and therefore matches nothing.

    Side note: if you use -E, you have to escape literal parentheses. Also, \d is not supported as far as I can tell, so you'd have to use either

    grep -P '\(\d{3}\)-\d{3}-\d{3}'
    

    or

    grep -E '\([[:digit:]]{3}\)-[[:digit:]]{3}-[[:digit:]]{3}'