Why do I have to quote an escaped character in a regular expression for grep, but not on online regex engines?

Why? because your shell interprets some special characters, such as \ in your example.

You are running into troubles because you do not protect the string that you try to pass as argument to grep via the Shell.

Several solutions:

  • singlequoting the string,
  • doublequoting the string (with doublequoting the shell will interpret several things, such as $variables , before sending the resulting string to the command),
  • or not use quoting (which I strongly advise against) but add backslashes in the right places to prevent the shell to interpret the next characters before sending it to the command.

I recommend to protect the string via single quotes, as it keeps almost everything literraly:

grep '9\.0' #send those 4 characters to grep in a single argument

The Shell pass the singlequoted string literally.

Note: The only thing you can't include inside a single quoted shell string is a single quote (as this ends the singlequoting). To include a singlequote inside a singlequoted shell string, you need to first end the singlequoting, immediately add an escaped singlequote \' (or one between doublequotes: "'" ) and then immediately reenter the singlequoting to continue the single quoted string : for exemple to have the shell execute the command grep a'b , you could write the parameter as 'a'\''b' so that the shell sends a'b to grep: so write: grep 'a'\''b' , or grep 'a'"'"'b'

If you insist on not using quoting, you need your shell to have a \\ to have it send a \ to grep.

grep 9\\.0  # ie: a 9, a pair \\, a ., and a 0 , and the shell interprets the pair \\ into a literal \

If you use doublequotes: you need to take into account that the shell will interprets several things first ($vars, \, etc). for exemple when it sees an unescaped or unquoted \, it waits the next character to decide how to interpret it. \w is seen as a single letter w, \\ is seen as a single letter \, etc.

grep "9\\.0"  # looks here the same as not quoting at all... 
    #but doublequoting allows you to have spaces, etc, inside the string

Turning the comments into an answer:

The problem is that \ is the escape character both for regexes and the shell. \. is to the shell the same as '.'. echo and set -x help understand, what the shell does:

> echo \.
.

> echo '\.'
\.

> echo \\.
\.


> set -x
> echo 9_00 | grep 9\.00
+ echo 9_00
+ grep 9.00
9_00

So if the command shall see the \ then it has to be protected by quotes or a second \.


To add to the other answer and comments, another thing that you can do to get grep to return what you want is to use the following:

grep -F 9.00 small.txt

Output:

9.00

The -F makes grep see the pattern as a fixed string and not a regular expression so that it will only return lines with that exact string. Because of this, you don't even need to escape the . or use quotes because it will only match 9.00 exactly instead of seeing the . as any character.