bash - 将命令和管道存储在变量中

3

有人能解释一下为什么AB的行为不同吗?

A=`echo hello how are you | wc -w`

并且

CMD="echo hello how are you | wc -w"
B=`$CMD`

它们给出不同的结果:

$echo $A
4

$echo $B
hello how are you | wc -w

我想要的是一个命令在一个变量中,可以在脚本的多个地方执行并得到不同的值进行比较。 这过去效果很好,但如果命令中有管道符号,则无法正常工作。

4
将shell语法(例如管道、引号等)存储在变量中是行不通的。变量是用于数据,而不是可执行代码。如果你想要存储可执行代码,请使用函数,这就是它们的用途。参见BashFAQ#50:“我试图将命令放入变量中,但复杂的情况总是失败!”以及许多关于此问题的先前提问(但请避免所有涉及“eval”的建议——它是一个巨大的漏洞源)。 - Gordon Davisson
1个回答

4
  • ``(即反引号)或 $() 在 bash 中被称为命令替换
  • "" - 例如用于保留字符的字面值,即数据。
  1. 在第一个示例中,执行命令 echo hello how are you | wc -w 并将其值 4 分配给 A,因此您获得了 4
  2. 在第二个示例中,它是将一个字符串赋值给变量 B,通过 `$CMD`| 不会被"评估",因为有延迟单词拆分(有关详细信息,请参见这里),因此您将得到 hello how are you | wc -w

您可以使用 eval 命令来完成所需操作,如下所示:

CMD="echo hello how are you | wc -w"
echo `eval $CMD`            # or just eval "$CMD"
# Output is 4

2
将字符串赋值给变量B,并且通过$CMD不对其进行“评估”。如果是这种情况,那么B将等于“echo hello how are you | wc -w”,但它并不等于该值,而是等于“hello how are you | wc -w”。因此,echo命令确实被执行了,只是没有管道传递到wc - k314159
1
@k314159 调整了我的回答。 - m19v
我仍然不明白为什么要运行echo而不是管道的逻辑...但感谢提供eval解决方案! - Martin Massera
1
由于“延迟词拆分”,管道未被评估,请参见https://unix.stackexchange.com/a/388352/393118获取更多信息。我也在我的答案中添加了链接。 - m19v
1
重要的是使用引号 -- eval "$CMD",而不是eval $CMD。否则,如果您的字符串拆分包含任何通配符,可能会将文件名注入到代码中。 - Charles Duffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接