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

标签 bash pipe

下面的代码可以正常工作

#!/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/

相关文章:

bash - 如何在 bash 中将一行拆分为由一个或多个空格分隔的单词?

perl - 无需正则表达式的简单搜索和替换

C 中命名管道的消费者 - 生产者问题

linux - BASH 嵌套进程替换

bash - 如何将多个命令通过管道传输到 shell 中的单个命令? (嘘,庆典,...)

linux - bash: [: 1+1: 预期的整数表达式

linux - Bash:模式之间的 sed/grep(仅包括第一个模式)

regex - 无法使提到的正则表达式在 sed 命令中工作

javascript - Node js : piping data to multiple streams

go - 如何将curl通过管道传输到Go程序中?