Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use grep to search for text containing square brackets("[ ]") in Linux

Tags:

regex

linux

grep

I am trying to searching a file to for text containing "[]" brackets. For example,

list[1];
i[ab1];

I tried grep -i \[[a-z||1-9]*\] myfile. But it doesn't work. These square brackets are special characters. I don't know how to escaping there special meaning. Can anybody give any suggestion?

like image 366
Jerry Avatar asked Oct 29 '15 19:10

Jerry


2 Answers

[ is a special character in a regular expression, since it is used to denote a range (just as you use it for in the subexpression [a-z||1-9]). You need to escape it so that grep will interpret it as a literal [ character; you do this by preceeding it with a backslash.

However, backslashes are also escape characters in the shell. To pass a single backslash to grep, you need to double it on the shell command line! You also need to escape the | characters and really should escape the * character, since these are also special to the shell:

grep -i \\[[a-z\|\|1-9]\*\\] myfile

It gets a bit easier if you just enclose the whole string in double quote marks:

grep -i "\\[[a-z||1-9]*\\]" myfile

Note that you still need to double the backslashes, as they can escape characters in a quoted string too. Even better would be to use a string enclosed with single quotes, in which backslashes don't act as an escape:

grep -i '\[[a-z||1-9]*\]' myfile
like image 187
davmac Avatar answered Oct 19 '22 04:10

davmac


You are not escaping enough. The shell interprets and peels off the backslashes before grep sees them.

A good general guidance is to always put your regular expressions in single quotes.

grep -i '\[[a-z1-9]*\]' myfile

The || seemed like a misunderstanding so I took it out. Between square brackets you simply put one of each character which is allowed in the match.

The square brackets have a similar meaning in the shell, which is why the first backslash only escapes them from the shell, not from grep. ls [*] will find files named literally with a single asterisk, not all files, or all files whose name is in square brackets. (Using ls here as an example with the caveat that you usually do not want to use ls in scripts; and just ls will list all files; and echo [*] will also list all files matching the wildcard expression -- though in Bash out of the box, if you get no matches, the wildcard will not be expanded, and so the error message might confusingly suggest that the wildcard didn't work.)

Not quoting arguments can be very dangerous, because the outcome of an unexpected wildcard expansion will depend on which files exist in the current directory. Behold:

vnix$ echo '|' >myfile

vnix$ grep -i \[[a-z||1-9]*\] myfile
grep: brackets ([ ]) not balanced
-bash: 1-9]*]: command not found

vnix$ grep -i \[[a-z\|\|1-9]*\] myfile

vnix$ # Right.  No matches.  But watch:

vnix$ touch '[|]'

vnix$ grep -i \[[a-z\|\|1-9]*\] myfile
|

vnix$ # !?! WTF?

vnix$ printf '<%s>\n' grep -i \[[a-z\|\|1-9]*\] myfile
<grep>
<-i>
<[|]>
<myfile>

So -- the shell expanded the unquoted regular expression as a wildcard when there was a matching file and you ended up grepping for something else than what you thought you were.

like image 1
tripleee Avatar answered Oct 19 '22 05:10

tripleee