下面的代码可以正常工作
#!/bin/bash
while true; do
echo $(pwd | awk '{print "dir: "$1}')
sleep 1
done
但我需要将命令放在一个变量中,就像这样。
#!/bin/bash
COMMAND=pwd | awk '{print "dir: "$1}'
while true; do
echo $($COMMAND)
sleep 1
done
第一个片段执行得很好,并打印出类似 dir:/present/directory
的内容。第二个片段只打印空行。为什么会这样?我该如何解决?
我使用的命令没有任何意义。我只需要使用一个管道并选择这些命令来演示它。
最佳答案
如果你喜欢危险的生活,答案是eval
:
#!/bin/bash
COMMAND="pwd | awk '{print \"dir: \"\$1}'"
while true
do
echo $(eval $COMMAND)
sleep 1
done
为什么危险?很难控制 eval
发生的事情,如果您接受来自幼稚(更不用说恶意)用户的命令字符串,情况会加倍。另请注意,我必须非常小心地引用包含命令的字符串。
为什么问题中的版本 2 不起作用?
COMMAND=pwd | awk '{print "dir: "$1}'
坦率地说,这条线并没有按照您的想法行事。
这是一个管道,第一个“命令”是字符串赋值 COMMAND=pwd
被视为空命令的环境变量,它不向 awk
发送数据>。完成后,$COMMAND
中的值是一个空字符串(既因为子 shell 与管道一起使用,也因为 COMMAND=pwd
仅在(空) 命令被执行),因此循环回显执行空字符串的结果——这也是一个空字符串。因此空白行。
This works for me but I'm having an issue with adding a tab in the AWK printout, and I think it's because of the escaping. If I have
COMMAND="ls -l | awk '{print \$8 \$9}'"
, how would I insert a tab\t
between the$8
and$9
?
哎哟,恶心!
如果您在 $8
和 $9
之间的源代码中有一个制表符,awk
会将其视为通用空白并粘贴 $8
和 $9
一起出现在输出中。要在输出中获取制表符,您需要一个包含制表符的带引号的字符串,或者两个字段之间包含 \t
的带引号字符串,或者您将使用 printf ()
使用合适的格式字符串。
因此,原则上,您可能需要:
COMMAND='ls -l | awk '\''{printf "%s\t%s\n", $8, $9}'\'
我已将字符串改为单引号,因为它们更容易理解。无论您使用单引号还是双引号,命令本身都包含两者,因此您必须担心如何进行转义。 '\''
序列是将单引号嵌入到单引号字符串中的方式;第一个单引号结束当前单引号字符串;反斜杠单引号添加一个单引号,最后一个单引号重新启动一个字符串。最后的序列'\'
也可以写成'\'''
,但是最后两个引号是零长度的单引号字符串,所以我去掉了.
这会产生带有制表符的漂亮输出;你可以通过运行来验证:
eval $COMMAND
echo $(eval $COMMAND)
完全取消了所有仔细的间距,将整个文件和时间列表展平为一行,每个“单词”与下一个“单词”之间用空格分隔。
您可以通过强制 echo
遵守间距(和换行符)来解决该问题:
echo "$(eval $COMMAND)"
但这提出了一个问题:“为什么不只使用 eval $COMMAND
?”
(测试:bash 3.2.48 Mac OS X 10.7.4。)
关于bash - 如果命令在变量中,则在子 shell 中执行管道命令不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12135259/