bash 中包含命令替换的变量

Inf*_*per 2 bash

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

在我的交互式 bash shell 中输入

x='$(id)'
$x
$(echo $x)
Run Code Online (Sandbox Code Playgroud)

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

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 扩展。我对在我的问题中运行实际脚本不感兴趣。

Gil*_*il' 5

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

\n

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

\n

对比:

\n
x=\'@(id)\'\nshopt -s extglob\necho /none/$x /usr/bin/$x\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

在 bash 手册中,相关句子位于Shell Expansions部分的开头。

\n
\n

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

\n
\n

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

\n

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

\n