变量中的执行命令不执行管道的后半部分

时间:2017-06-17 14:08:25

标签: bash variables pipe

我发现从变量扩展的命令不会在管道中运行后面的部分。例如,如下test.sh

#!/bin/bash

y='echo hello man | awk "{print \$1}"'
$y
eval $y

y='echo hello'
$y

脚本的输出是:

hello man | awk "{print \$1}"
hello
hello

第一个$y仅执行echo hello man但不执行管道的awk "{print $1}"。那是什么原因?
我的bash版本为4.3.48

1 个答案:

答案 0 :(得分:3)

那是因为在管道和重定向完成之后变量被扩展了。因此,在这种情况下,|只是echo的另一个参数,而不是由shell解释的管道。

推荐阅读:http://mywiki.wooledge.org/BashFAQ/050

执行命令时

echo hello man | awk '{print $1}'

shell将看到|并设置管道,一方面它将运行命令echo hello man而另一方awk '{print $1}'。然后命令将进行单词拆分,因此您可以使用2个参数运行命令echohelloman。另一方面,您使用单个参数运行命令awk(因为引用)"{print \$1}"

当该命令作为字符串存储时,shell首先查看命令$y并且看不到重定向。然后它展开$y,然后对其进行分词。它会扩展到相同的字符串,但现在它对于重定向来说太迟了。因此它被分为echohelloman|awk"{print\$1}"(注意) awk的参数现在被拆分,因为字符串中的引号是字符串的一部分,而不是语法的一部分)

该列表中的第一个单词是echo以便命令,其余所有单词都作为参数传递给它,这就是你看到输出的原因

hello man | awk "{print \$1}"

当你执行eval行时,它会接受相同的字符串并告诉bash解析它,好像它已经被输入一样,这样管道再次变得合成并导致管道。

因为echo将其论点置于同一条线上,所以有时看看发生了什么有点困难,如果我们用printf '%s\n'替换它,每个参数都将成为它自己的行虽然:

$ y='printf %s\n hello man | awk "{print \$1}"'
$ $y
hello
man
|
awk
"{print
\$1}"