我发现从变量扩展的命令不会在管道中运行后面的部分。例如,如下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
。
答案 0 :(得分:3)
那是因为在管道和重定向完成之后变量被扩展了。因此,在这种情况下,|
只是echo
的另一个参数,而不是由shell解释的管道。
推荐阅读:http://mywiki.wooledge.org/BashFAQ/050
执行命令时
echo hello man | awk '{print $1}'
shell将看到|
并设置管道,一方面它将运行命令echo hello man
而另一方awk '{print $1}'
。然后命令将进行单词拆分,因此您可以使用2个参数运行命令echo
:hello
和man
。另一方面,您使用单个参数运行命令awk
(因为引用)"{print \$1}"
当该命令作为字符串存储时,shell首先查看命令$y
并且看不到重定向。然后它展开$y
,然后对其进行分词。它会扩展到相同的字符串,但现在它对于重定向来说太迟了。因此它被分为echo
,hello
,man
,|
,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}"