bash/sh -c不能使用多个管道

jol*_*olt 5 linux bash shell

所以,命令:

dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'
Run Code Online (Sandbox Code Playgroud)

当直接从shell执行时,就像应该的那样工作,输出:

[sdb]
[sdc]
[sda]

但是,当我启动它时:

sh -c "dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'"
# or
bash -c "dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'"
Run Code Online (Sandbox Code Playgroud)

我明白了:

[ 2.460353] sd 1:0:0:0: [sdb] Attached SCSI disk
[ 2.461348] sd 2:0:0:0: [sdc] Attached SCSI disk
[ 2.464181] sd 0:0:0:0: [sda] Attached SCSI disk

这清楚地表明最后一个管道没有执行.

我究竟做错了什么?

edu*_*ffy 14

$5的评估过早.将其更改为\$5.

如果要替换bashecho,则会看到$5正在替换为空字符串:

 % echo "dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'"
 dmesg | grep 'Attached SCSI disk' | awk '{ print }'
Run Code Online (Sandbox Code Playgroud)

因此,当bash评估命令时,awk将打印整行,而不是第五个字段.

当你逃避美元符号时(通过预先用反斜杠预先添加),变量将$5被保留:

% echo "dmesg | grep 'Attached SCSI disk' | awk '{ print \$5}'"
dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'
Run Code Online (Sandbox Code Playgroud)

  • 在传递给`sh`或`bash`之前,整个字符串都要经过参数扩展.因为它是双引号,`$ 5`被解释为shell位置参数.(单引号不保护它;它们也只是字符串中的字符.) (6认同)
  • 另外,您可以将其简化为:`dmesg | awk'/附加SCSI磁盘/ {打印$ 5}'` (5认同)