bash 中包含命令替换的变量

bash 中包含命令替换的变量

我试图了解 bash 中的 shell 扩展(GNU bash,版本 4.4.20(1)-release (i686-pc-linux-gnu))。

在我的交互式 bash shell 中输入

x='$(id)'
$x
$(echo $x)

我预计最后两行中的任何一行都会出现以下形式的错误

bash: uid=xxx(user): command not found

但得到了

bash: $(id): command not found

我不明白为什么这里不发生命令替换。不是应该通过变量扩展来实现吗?我的猜测是它与 Shell 操作有关,如此处所述https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Operation

有人可以解释这种行为吗?

我只是有兴趣更准确地理解 bash 扩展。我对在我的问题中运行实际脚本不感兴趣。

答案1

$(…)是命令替换(“进程替换”是<(…)等等)。变量替换和命令替换发生在同一遍中,在字符串中从左到右。这些替换结果中唯一发生的事情是分词和通配符。

因此x='$(id)'设置x为 5 个字符的字符串$(id)。然后,为了运行$x,shell 将替换$x为值$(id)。它不包含任何空格或通配符,因此它被视为命令名称。

对比:

x='@(id)'
shopt -s extglob
echo /none/$x /usr/bin/$x

假设该文件/none/id不存在但/usr/bin/id确实存在,则该echo命令将扩展为三个单词:(echo显然)、/none/@(id)(glob 模式/none/@(id)不匹配任何内容,因此保持不变)和/usr/bin/id(glob 模式/usr/bin/@(id)匹配一​​个文件,因此将其替换为匹配的单元素列表)。

在bash手册中,相关的句子位于外壳扩展部分。

展开的顺序是:大括号展开;波形符扩展、参数和变量扩展、算术扩展和命令替换(以从左到右的方式完成);分词;和文件名扩展。

两个分号之间的所有内容都是一次传递。每一遍都基于前一遍的结果。

请注意,单个句子(即使是像我上面引用的那样复杂的句子)无法讲述整个​​故事。 shell 语义很复杂。我怀疑任何 shell 的手册都包含所有特殊情况的详细信息。这POSIX规范更正式,但不涵盖 bash 特定的扩展,甚至它留下了一些未定义的非常奇怪的情况。

答案2

这是引用。单引号 ( ') 定义文字字符串,并且不能发生插值或转义。双引号 ( ") 允许插值和转义。

这是一个例子:

$ x='$(id)'
$ echo 'The variable x contains the value \"$x\"'
The variable x contains the value \"$x\"
$ echo "The variable x contains the value \"$x\""
The variable x contains the value "$(id)"

$ x="$(id)"
$ echo "The variable x contains the value \"$x\""
The variable x contains the value "uid=1000(myusername)..."

这是基于单引号与双引号的插值和转义的另一个示例:

$ echo 'The current directory is $PWD according to the variable \"\$PWD\".'
The current directory is $PWD according to the variable \"\$PWD\".

$ echo "The current directory is $PWD according to the variable \"\$PWD\"."
The current directory is /tmp according to the variable "$PWD".

相关内容