如果命令在变量中,则在子shell中执行管道命令不起作用

gsi*_*011 2 bash pipe

以下代码工作正常

#!/bin/bash

while true; do
     echo $(pwd | awk '{print "dir: "$1}')
     sleep 1
done
Run Code Online (Sandbox Code Playgroud)

但我需要命令在变量中,就像这样.

#!/bin/bash                                                                     

COMMAND=pwd | awk '{print "dir: "$1}'
while true; do
     echo $($COMMAND)
     sleep 1
done
Run Code Online (Sandbox Code Playgroud)

第一个片段执行正常,并打印出类似的东西dir: /present/directory.第二个片段只打印空白行.为什么这样,我该如何解决?

我使用的命令没有意义.我只需要使用管道并选择这些命令来演示它.

Jon*_*ler 5

如果你喜欢危险的生活,答案是eval:

#!/bin/bash                                                                     

COMMAND="pwd | awk '{print \"dir: \"\$1}'"
while true
do
    echo $(eval $COMMAND)
    sleep 1
done
Run Code Online (Sandbox Code Playgroud)

为什么危险?eval如果您接受来自天真(更不用说恶意)用户的命令字符串,那么很难控制正在发生的事情.还要注意我必须引用包含命令的字符串.

为什么问题中的第2版没有工作?

COMMAND=pwd | awk '{print "dir: "$1}'
Run Code Online (Sandbox Code Playgroud)

这句话并没有按照你的想法做到,直言不讳.

它是一个管道,第一个'命令'是字符串赋值,它COMMAND=pwd被视为空命令的环境变量,它不发送任何数据awk.完成后,值in $COMMAND是一个空字符串(因为子管道与管道一起使用,因为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}'\'
Run Code Online (Sandbox Code Playgroud)

我已经切换到字符串周围的单引号,因为它们更容易理解.无论您使用单引号还是双引号,命令本身都包含两者,因此您必须担心如何进行转义.该'\''序列是如何嵌入一个单引号变成一个单引号字符; 第一个单引号结束当前单引号字符串; 反斜杠单引号添加单引号,最后一个单引号重新启动单个字符串.最后的序列'\'也可以写'\''',但最后两个引号是一个零长度的单引号字符串,所以我放弃它们.

这会产生带有标签的不错输出; 您可以通过运行验证:

eval $COMMAND
Run Code Online (Sandbox Code Playgroud)

echo $(eval $COMMAND)完全撤消所有小心间距,压扁文件和时代的整个列表与用空格从下分隔每个"单词"单行.

您可以通过强制echo尊重间距(和换行符)来解决该问题:

echo "$(eval $COMMAND)"
Run Code Online (Sandbox Code Playgroud)

但是这提出了"为什么不只使用eval $COMMAND?"的问题.

(测试:bash 3.2.48 Mac OS X 10.7.4.)