8

I need to egrep a string that isn't known before runtime and that I'll get via shell variable (shell is bash, if that matters). Problem is, that string will contain special characters like braces, spaces, dots, slashes, and so on.

If I know the string I can escape the special characters one at a time, but how can I do that for the whole string?

Running the string through a sed script to prefix each special character with \ could be an idea, I still need to rtfm how such a script should be written. I don't know if there are other, better, options.

I did read re_format(7) but it seems there is no such thing like "take the whole next string as literal"...

EDIT: to avoid false positives, I should also add newline detection to the pattern, eg. egrep '^myunknownstring'

Luke404
  • 10,282
  • 3
  • 25
  • 31
  • how to escape regular expressions in bash http://stackoverflow.com/questions/11856054/bash-easy-way-to-pass-a-raw-string-to-grep/16951928#16951928 – Riccardo Galli Jun 06 '13 at 00:29

3 Answers3

7

If you need to embed the string into a larger expression, sed is how I would do it.

s_esc="$(echo "$s" | sed 's/[^-A-Za-z0-9_]/\\&/g')" # backslash special characters
inv_ent="$(egrep "^item [0-9]+ desc $s_esc loc .+$" inventory_list)"
geekosaur
  • 59,309
  • 11
  • 123
  • 114
4

Use the -F flag to make the PATTERN a fixed literal string

$ var="(.*+[a-z]){3}"
$ echo 'foo bar (.*+[a-z]){3} baz' | grep -F "$var" -o
(.*+[a-z]){3}
SiegeX
  • 135,741
  • 24
  • 144
  • 154
  • 1
    thanks for the tip, that's correct, but I forgot to specify I also need to match the string _only_ at beginning of line. I added this detail to the question. – Luke404 Mar 20 '11 at 16:20
0

Are you trying to protect the string from being incorrectly interpreted as bash syntax or are you trying to protect parts of the string from being interpreted as regular expression syntax?

For bash protection:

grep supports the -f switch:

-f FILE, --file=FILE
    Obtain patterns from FILE, one per line.  The empty file contains zero patterns, and therefore matches nothing.

No escaping is necessary inside the file. Just make it a file containing a single line (and thus one pattern) which can be produced from your shell variable if that's what you need to do.

# example trivial regex
var='^r[^{]*$'
pattern=/tmp/pattern.$$
rm -f "$pattern"
echo "$var" > "$pattern"
egrep -f "$pattern" /etc/password
rm -f "$pattern"

Just to illustrate the point.

Try it with -F instead as another poster suggested for regex protection.

sorpigal
  • 25,504
  • 8
  • 57
  • 75