0

I have a file with the below contents:

sh-4.2$ cat file1
example of multiple
pattern
this is an
example of multipole
sorry multiple
pattern matching
using grep
so the example is the
file itself
-example
-multiple
-bye
tata
!

While searching for "-example" in the above file, the grep command is not giving the desired output. I know if the pattern contains '-' then -e option should be used:

In the first example I used -example directly without any quotes:

sh-4.2$ grep -example file1
example of multiple
example of multipole
so the example is the
-example

-example with single quotes:

sh-4.2$ grep '-example' file1
example of multiple
example of multipole
so the example is the
-example

-example with double quotes and escape characters

sh-4.2$ grep "\-example" file1
-example
sh-4.2$
  • 1
    What is the desired output? Seems that grep works ok by your tests. – George Vasiliou Dec 17 '16 at 8:34
  • when using double quotes with escape sequence , i am getting the desired output, but when i use single quotes the desired output is not coming – Pankaj Pandey Dec 17 '16 at 8:36
  • So the question is about single vs double quotes in grep and bash gemerally... big story. – George Vasiliou Dec 17 '16 at 8:47
  • yup.. that's what it is about – Pankaj Pandey Dec 17 '16 at 9:01
  • 2
    So, what exactly is the question? "Why doesn't grep return what I expect when I use single quotes?" or "How do I do this using single quotes with grep?" @Pankaj-Pandey, could you edit the question to make it clearer what it is you're asking? – John N Dec 17 '16 at 9:10
3

Well, you know that the search pattern contains a '-', and you know that when the search pattern contains a '-' you need to use the -e flag. Since you're not using the -e flag the shell is interpreting your "pattern" as an argument (and a parameter) instead. You can see that with:

$ grep "-foo" file1
grep: oo: No such file or directory

By extension, your code grep "-example" file1 is telling the shell that you want to run grep with the -e argument and a parameter "xample".

This is the same problem we run into when we try something like rm -my-silly-file-name - it won't work, and we need to use something like rm ./-my-silly-file-name instead. Another workaround would be rm -- -my-silly-file-name. We can use that idiom here:

$ grep -- "-example" < file1
-example

The "--" tells the shell that everything after it is not an argument.

Alternatively, you can simply escape the "-" with a "\", as you've seen:

grep "\-example" file1

This article goes into some details about quoting: the relevant part is Parameters and backquoted commands that should be interpreted by the shell are enclosed in double quotes. When you use double-quotes, the contents are interpreted by the shell.

2

You "know if the pattern [begins with] '-' then -e option should be used" but you are not using it when you should. grep -e -example file1 will give you the expected result.

Here is what is actually executed in each of your examples:

  • grep -example file1 => grep -e xample file1 (-e is necessary)
  • grep '-example' file1 => grep -e xample file1 (-e is necessary)
  • grep "\-example" file1 => grep \-example file1 (-e is not necessary)
1

An argument that starts with - is taken as an option.

In your first two cases, the first argument passed to grep is -example, which grep understands as -e xample (xample argument to the -e option, so search for xample).

In the third case \-example is passed to grep. As it doesn't start with -, it's not taken as an option. It's taken as a regexp instead. However the behaviour for \- is unspecified as per POSIX, so you have no guarantee as to what it matches. With most grep implementations, \- will match a -, however you can imagine grep implementations where \- may be a special operator (see for instance GNU grep where \+ is a special operator and doesn't match a literal +).

If you want -example not to be taken as an option, you need either:

  • grep -- -example file. The -- marks the end of options. Anything after it is a non-option (so the first argument the pattern to search and the rest the list of files to look in).
  • grep -e -example file. Here, -example is taken as the argument to the -e option.

That's the kind of reason why you should get used to writing:

grep -e "$pattern" file

Or

grep -- "$pattern" file

if you can't guarantee $pattern won't start with -.

Note that here, you could also write it:

grep '[-]example' file

Though see Bracket expression (without ranges) matching unexpected character in bash about possible complications with that approach.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.