我正在尝试使用管道运行命令但收到错误:
echo abc | `echo "grep a | grep b"`
grep: |: No such file or directory
grep: grep: No such file or directory
grep: b: No such file or directory
代码有什么问题?
预期结果是要执行以下命令:
echo abc | grep a | grep b
结果是
abc
目前尚不清楚您要做什么,但这是您正在做的事情:
echo "grep a | grep b"
输出字符串grep a | grep b
。
这是反引号的输出。您在 shell 需要命令的位置使用反引号,所以 "grep 'a' '|' 'grep' 'b'" 尝试作为命令行,所有标记都按字面解释(我添加了单引号以使其更清晰,希望如此),因此 shell 忽略输入echo
并尝试查找正则表达式a
在命名文件中。您显然没有名为“|”、“grep”或“b”的文件,因此您会收到一条错误消息。
你可能想要的是
echo abc | grep a | grep b
它在“echo”的输出中搜索“a”,然后在第一个 grep 的输出中搜索“b”。因为abc
匹配正则表达式a
,第一个grep
成功,所以打印匹配行;并且因为它也匹配正则表达式,所以它也b
被最终打印出来grep
。
要对此进行扩展,请尝试以下操作:
sh$ echo abc; echo bcd; echo xya
abc
bcd
xya
sh$ ( echo abc; echo bcd; echo xya ) | grep a # print lines matching a
abc
xya
sh$ (echo abc; echo bcd; echo xya ) | grep a | grep b # print lines matching a and b
abc
目前尚不清楚您为什么使用反引号;如果这不是您想要实现的目标,请更详细地解释您想要实现的目标。
如果要查找匹配 a 或 b 的行,请尝试以下操作:
sh$ ( echo abc; echo bcd; ) | grep '[ab]'
仅当您让 bash 解析器看到管道字符时,它才是特殊的。您使用“”引用它,因此它不再特殊,并grep
认为您希望它a
从文件|
中grep 字符串grep
和b
.
一般来说,一旦你转义了作为 shell 语法一部分的特殊字符,你就不能在以后取消它(因为这样就没有办法处理实际调用的文件|
- 这不是一个好主意,但它是可能,并且 bash 不应该无法处理它。)
使此类字符再次被视为特殊字符的唯一方法是将其重新提交给 shell 解释器的全新调用,这就是 Robert Martin 的解决方案所做的。
Triplee 的解释与我认为正在发生的事情非常接近(如果不是说完全相同的话)。“Clasic Shell Scripting” [Robbins & Beebe],第 7.8.1 节,实际上对与我原来的问题相关的问题有一个很好的解释。
如果你写
listpage="ls | more"
$listpage
然后你会遇到类似的问题,其中 '|' & 'more' 被视为 ls 的参数。给出的原因是,在 shell 完成变量替换时(步骤 5/10),原始输入已经被分解为标记(其中 | 是一个)(步骤 1/10)。所以'|' 失去其特殊意义并被视为论据。
但是,如果你写:
eval $listpage
eval 导致 shell 在第 1 步重新启动,其中 '|' 字符被视为特殊标记。
这部分是错误的:
$ `echo "grep a | grep b"`
因为反引号不理解管道。试试这个做同样事情的替代品:
$ echo "grep a | grep b" | sh