如果你喜欢危险的生活,答案是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
. 完成后,in 的值$COMMAND
是一个空字符串(既是因为与管道一起使用的子shell,也是因为COMMAND=pwd
仅在执行(空)命令时应用),所以循环回显了执行空字符串的结果——这也是一个空字符串。因此,空白行。
这对我有用,但我在 AWK 打印输出中添加选项卡时遇到问题,我认为这是因为转义。如果有COMMAND="ls -l | awk '{print \$8 \$9}'"
,我将如何在和\t
之间插入一个制表符?$8
$9
哎哟,哎呀!
如果您在$8
and之间的源中有一个选项卡$9
,awk
则将其视为通用空格并将其粘贴$8
并$9
一起粘贴到输出中。要在输出中获取选项卡,您需要一个包含选项卡的带引号的字符串,或者一个包含\t
在两个字段之间的带引号的字符串,或者您将使用printf()
带有合适格式字符串的 a。
所以,原则上,你可能想要:
COMMAND='ls -l | awk '\''{printf "%s\t%s\n", $8, $9}'\'
我已经切换到字符串周围的单引号,因为它们更容易理解。无论您使用单引号还是双引号,命令本身都包含两者,因此您必须担心如何进行转义。序列是您如何将'\''
单引号嵌入到单引号字符串中;第一个单引号结束当前单引号字符串;反斜杠单引号添加一个单引号,最后一个单引号重新启动单个字符串。最后的序列'\'
也可以写'\'''
,但是最后两个引号是零长度的单引号字符串,所以我把它们去掉了。
这会产生带有标签的漂亮输出;您可以通过运行来验证:
eval $COMMAND
完全取消了所有仔细的echo $(eval $COMMAND)
间距,将整个文件和时间列表展平为一行,每个“单词”与下一个“单词”用空格分隔。
echo
您可以通过强制遵守间距(和换行符)来解决该问题:
echo "$(eval $COMMAND)"
但这提出了“为什么不使用 just eval $COMMAND
?”的问题。
(测试:bash 3.2.48 Mac OS X 10.7.4。)