$() 是子shell吗?

lee*_*d00 65 bash subshell syntax

我理解子shell的语法是(<commands...>)$()只是一个可以从中检索变量值的子shell?

注意:根据文档中的不同措辞,这适用于 bash 4.4。

Gil*_*il' 97

$(…)根据定义,它是一个子 shell:它是 shell 运行时状态¹的副本,并且对子 shell 中的状态所做的更改对父级没有影响。子shell通常通过fork一个新进程来实现(但在某些情况下,一些shell可能会对此进行优化)。

它不是您可以从中检索变量值的子shell。如果对变量的更改对父级产生影响,则它不会是子 shell。它是一个子shell,其父级可以检索其输出。由创建的子shell 将$(…)其标准输出设置为管道,父级从该管道读取并收集输出。

还有其他几个构造可以创建子shell。我认为这是 bash 的完整列表:

  • 用于分组( … )的子外壳:除了创建子外壳并等待它终止之外什么都不做)。与{ … }纯粹出于语法目的而不创建子shell 的组命令形成对比。
  • 背景… &创建一个子shell并且不等待它终止。
  • Pipeline… | …创建两个子shell,一个用于左侧,一个用于右侧,并等待两者终止。shell 创建一个管道并将左侧的标准输出连接到管道的写入端,将右侧的标准输入连接到读取端。在某些 shell(ksh88、ksh93、zsh、带有lastpipe选项设置和有效的bash )中,右侧在原始 shell 中运行,因此管道构造仅创建一个子 shell。
  • 命令替换:($(…)也拼写`…`)创建一个子shell,其标准输出设置为管道,在父级中收集输出并扩展为该输出,减去其尾随换行符。(并且输出可能会进一步受到拆分和通配,但那是另一回事了。)
  • 进程替换<(…)创建一个子shell,其标准输出设置为管道并扩展为管道的名称。父进程(或一些其他进程)可以打开管道与子外壳通信。>(…)做同样的事情,但在标准输入上使用管道。
  • Coprocesscoproc …创建一个子shell并且不等待它终止。子shell 的标准输入和输出都设置为一个管道,父级连接到每个管道的另一端。

¹与运行单独的外壳相反

  • @user1717828 什么?为什么?远程变量扩展与这个问题有什么关系?我不会在我的答案中包含整个 shell 手册。 (4认同)

Ign*_*ams 23

来自 bash 4.4 版的 bash(1) 手册页,“扩展”部分,“命令替换”小节:

Bash 通过command在子 shell 环境中执行来执行扩展[...]

  • 这也是 [POSIX 明确指定的](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_03)。 (10认同)
  • @dr01 相反,bash 4.4 更改了该句子的措辞以包含“subshel​​l”一词。这是一个澄清:手册明确提到各种其他构造是子外壳,但直到 4.4 才明确说明命令替换。 (7认同)

Isk*_*tvo 7

是的,( commands... )是一个bashcommands...在另一个进程中执行的子shell 。

唯一的区别$( commands... )是,这部分代码在执行后将commands...替换为commands...写入stdout.