Answers:
$(…)
从定义上讲,它是一个子Shell:它是Shell运行时状态¹的副本,并且对该子Shell中状态的更改对父级没有影响。子外壳程序通常是通过派生新进程来实现的(但某些外壳程序在某些情况下可能会对此进行优化)。
它不是您可以从中检索变量值的子外壳。如果对变量的更改对父级有影响,那么它将不是子shell。这是一个子shell,其父级可以检索其输出。由创建的子外壳将$(…)
其标准输出设置为管道,并且父级从该管道读取并收集输出。
还有其他几种创建子外壳的构造。我认为这是bash的完整列表:
( … )
的子shell :除了创建子shell并等待其终止之外,什么都不做。与{ … }
纯粹出于语法目的而命令的组相反,而不创建子shell。… &
创建一个子外壳,不等待它终止。… | …
创建两个子外壳,一个用于左侧,一个用于右侧,然后等待两者终止。外壳程序创建一个管道,并将左侧的标准输出连接到管道的写入端,并将右侧的标准输入连接到读取端。在某些shell(ksh88,ksh93,zsh,bash中具有设置的lastpipe
选项和有效选项)中,右侧在原始shell中运行,因此管道构造仅创建一个子shell。$(…)
也拼写为`…`
)创建一个子shell,其标准输出设置为管道,收集父级中的输出,并扩展到该输出,减去尾随的换行符。(并且输出可能会进一步分裂和阻塞,但这是另一回事了。)<(…)
创建一个子shell,并将其标准输出设置为管道,然后扩展为管道的名称。父级(或其他进程)可以打开管道以与子外壳进行通信。>(…)
相同,但管道在标准输入上。coproc …
创建一个子外壳,不等待其终止。子外壳的标准输入和输出每个都设置为一个管道,其父级连接到每个管道的另一端。${...}
在答案中包含吗?
command | { read line; … }
(取决于外壳,line
流水线之后可能还是可能不可用)。所有方式都涉及一个子外壳,因为产生输出的命令必须独立于读取输入的外壳运行。如果命令是纯内部的(只有shell构造和内置命令,没有外部命令),则该shell可能不会创建子进程,但这只是一个优化,它仍会创建一个子shell。
从bash版本4.4中的bash(1)手册页的“ EXPANSION”部分,“ Command Substitution”子部分中:
Bash通过
command
在子shell环境中执行来执行扩展[...]
bash
页没有提到任何子外壳:Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.
我想知道这是否是故意的遗漏。