下面的代码运行良好
#!/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
的内容。第二个代码段只打印空行。为什么会这样?我该如何修复它?
我使用的命令没有任何意义。我只需要使用管道,并选择这些命令来演示它。
发布于 2012-08-27 01:16:01
如果你喜欢危险的生活,答案是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
仅在执行( empty )命令时应用),因此循环回显执行空字符串的结果-这也是一个空字符串。因此出现了一行空白。
这对我很有效,但我在AWK打印输出中添加制表符时遇到了问题,我认为这是因为转义的原因。如果我有
COMMAND="ls -l | awk '{print \$8 \$9}'"
,如何在$8
和$9
之间插入选项卡\t
?
哦,还有讨厌!
如果在$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。)
发布于 2012-08-27 01:17:55
单引号的使用使其中的所有内容都是字面上的。这意味着$不会被计算。
然而,在第二个示例中,您通过说$($COMMAND)来强制重新计算。这会导致'...$1‘再次被处理,这次没有引号。那么--瞧!它起作用了!
您可以通过交换“and”、使用双引号(以及在内部使用\或单引号)来解决此问题。
希望这能帮上忙
J
https://stackoverflow.com/questions/12135259
复制相似问题