以下代码可以正常使用
#!/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
的内容。第二个片段只打印空白行。为什么这样,我该如何解决?
我使用的命令没有意义。我只需要使用管道并选择这些命令来演示它。
答案 0 :(得分:5)
如果您喜欢危险地生活,答案是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'是字符串赋值COMMAND=pwd
,被视为空命令的环境变量,它不向awk
发送数据。完成后,$COMMAND
中的值是一个空字符串(两者都是因为管道使用的子shell,因为COMMAND=pwd
仅在执行(空)命令时应用了),所以循环回应执行空字符串的结果 - 这也是一个空字符串。因此空白行。
哎哟,哎呀!这对我有用,但我在AWK打印输出中添加标签时遇到问题,我认为这是因为转义。如果我有
COMMAND="ls -l | awk '{print \$8 \$9}'"
,我如何在\t
和$8
之间插入标签$9
?
如果您在$8
和$9
之间的来源中有一个标签,awk
会将其视为通用空格,并将$8
和$9
粘贴在一起在输出中。要在输出中获取标签,您需要包含标签的带引号的字符串,或者在两个字段之间包含\t
的带引号的字符串,或者您将使用合适的printf()
格式字符串。
所以,原则上,你可能想要:
COMMAND='ls -l | awk '\''{printf "%s\t%s\n", $8, $9}'\'
我已经切换到字符串周围的单引号,因为它们更容易理解。无论您使用单引号还是双引号,命令本身都包含两者,因此您必须担心如何进行转义。 '\''
序列是将单引号嵌入单引号字符串的方式;第一个单引号结束当前单引号字符串;反斜杠单引号添加单引号,最后一个单引号重新启动单个字符串。最后的序列'\'
也可以写成'\'''
,但最后两个引号是一个零长度的单引号字符串,所以我放弃它们。
这会产生带有标签的不错输出;您可以通过运行验证:
eval $COMMAND
echo $(eval $COMMAND)
完全撤消所有细心的间距,将整个文件列表和时间展平为一行,每个'word'与下一个空格隔开。
您可以通过强制echo
尊重间距(和换行符)来解决该问题:
echo "$(eval $COMMAND)"
但是这提出了“为什么不只使用eval $COMMAND
?”的问题
(测试:bash 3.2.48 Mac OS X 10.7.4。)
答案 1 :(得分:0)
使用单引号使其中的所有内容都是文字的。这意味着$不会被评估。
然而,在第二个例子中,您通过说$($ COMMAND)强制重新评估。这导致'... $ 1'再次被处理,这次没有引号。那么 - 瞧!它有效!
您可以通过切换“和”,使用双引号(以及使用\“内部或单引号)来解决此问题。
希望这有帮助,
Ĵ