grep 误读了变量中的模式

grep 误读了变量中的模式

我在放入转义模式时遇到问题grep

我的测试文件是:

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

如果我运行:

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

然后将输出复制到 grep 作为我得到的模式:

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

但是如果我将模式放入变量或反引号中,我会得到:

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

有人能告诉我为什么这会产生差异以及如何在变量中使用带引号的字符串作为grep模式吗?

答案1

问题是外壳逃逸\是 shell 中的特殊字符,也是grep.

在:

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

export_cc\ =\ \$\{dir\}/aaa/bbb/cccexport_cc = ${dir}/aaa/bbb/ccc在传递给 之前被 shell 解释为一个字符串grep。您可以使用斯特雷斯去检查:

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

命令替换:

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

如果没有双引号,则结果为命令替换曾是拆分和通配符由外壳分为三部分:export_cc\=\、 和\$\{dir\}/aaa/bbb/ccc。 shell 将它们视为三个字符串,转义所有反斜杠并将它们传递给grepas 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收到一个带有一个反斜杠,export_cc\后面什么都没有的模式,它显示了消息Trailing backslash

为了让它发挥作用,你需要双引号命令替换,并使用打印函数%s而不是%q

$ grep "$(printf %s 'export_cc = ${dir}/aaa/bbb/ccc')" file
export_cc = ${dir}/aaa/bbb/ccc

相关内容