2

I have a problem with escaped pattern put in grep.

My test file is:

export_cc = ${dir}/aaa/bbb/ccc
export_cc = ${dir}/aaa/bbb/eee
export_cc = ${dir}/aaa/bbb/ddd
export_cc = ${dir}/aaa/bbb/fff
export_cc = ${dir}/aaa/bbb/ggg

If I run:

~/programming/sandbox $ printf %q 'export_cc = ${dir}/aaa/bbb/ccc'
export_cc\ =\ \$\{dir\}/aaa/bbb/ccc

and then copy output to grep as the pattern I would get:

~/programming/sandbox $ grep export_cc\ =\ \$\{dir\}/aaa/bbb/ccc file
export_cc = ${dir}/aaa/bbb/ccc

But if I put pattern into the variable or backticks I would get:

~/programming/sandbox $ grep `printf %q 'export_cc = ${dir}/aaa/bbb/ccc'` file
grep: Trailing backslash 

Could someone tell me why this makes the difference and how to use quoted string in variable as a grep pattern?

cuonglm
  • 153,898

1 Answers1

3

The problem was shell escaping. \ is special character in shell, and also in grep.

In:

grep export_cc\ =\ \$\{dir\}/aaa/bbb/ccc file

export_cc\ =\ \$\{dir\}/aaa/bbb/ccc was interpreted by the shell to one string export_cc = ${dir}/aaa/bbb/ccc before passing to grep. You can use strace to check:

$ strace grep export_cc\ =\ \$\{dir\}/aaa/bbb/ccc file
execve("/bin/grep", ["grep", "export_cc = ${dir}/aaa/bbb/ccc",...

With Command Substitution:

grep `printf %q 'export_cc = ${dir}/aaa/bbb/ccc'` file

Without double quote, the result of Command Substitution was split and glob by the shell into three parts: export_cc\, =\, and \$\{dir\}/aaa/bbb/ccc. The shell treated them as three strings, escape all backslashes and pass them to grep as export_cc\\, =\\, \\$\\{dir\\}/aaa/bbb/ccc:

$ strace grep $(printf %q 'export_cc = ${dir}/aaa/bbb/ccc') file
execve("/bin/grep", ["grep", "export_cc\\", "=\\", "\\$\\{dir\\}/aaa/bbb/ccc",...

grep received a pattern with one backslash export_cc\ followed by nothing, and it shown the message Trailing backslash.

To make it works, you need to double quotes command substitution, and using printf with %s instead of %q:

$ grep "$(printf %s 'export_cc = ${dir}/aaa/bbb/ccc')" file
export_cc = ${dir}/aaa/bbb/ccc
cuonglm
  • 153,898
  • thank you very much for detailed answer, especially for mentioning strace which will help me with debugging shell commands. – user2551229 Jun 01 '15 at 17:47