我理解子 shell 语法是(<commands...>)
,$()
只是一个可以从中检索变量值的子 shell?
注意:这适用于 bash 4.4,基于其文档中的不同措辞。
答案1
$(…)
根据定义,它是一个子 shell:它是 shell 运行时状态的副本,并且在子 shell 中对状态进行的更改不会对父 shell 产生影响。子shell通常由以下方式实现分叉一个新的进程(但某些 shell 在某些情况下可能会对此进行优化)。
它不是您可以从中检索变量值的子 shell。如果变量的更改对父级产生影响,则它不会是子 shell。这是一个子shell,其输出家长可以检索。创建的子 shell$(…)
将其标准输出设置为管道,父 shell 从该管道读取并收集输出。
还有其他几种创建子 shell 的结构。我认为这是 bash 的完整列表:
- 子外壳为分组:
( … )
除了创建一个子 shell 并等待它终止之外什么也不做)。与{ … }
哪些组命令纯粹出于语法目的并且不创建子 shell 进行对比。 - 背景:
… &
创建一个子shell并且不等待它终止。 - 管道:
… | …
创建两个子 shell,一个用于左侧,一个用于右侧,并等待两个子 shell 都终止。 shell 创建一个管道,并将左侧的标准输出连接到管道的写入端,将右侧的标准输入连接到读取端。在某些 shell 中(ksh88、ksh93、zsh、bash 以及lastpipe
选项设置且有效),右侧在原始 shell 中运行,因此管道构造仅创建一个子 shell。 - 命令替换:
$(…)
(也拼写为`…`
)创建一个子 shell,其标准输出设置为管道,收集父级中的输出并扩展到该输出,减去其尾随换行符。 (输出可能会进一步受到分裂和通配的影响,但那是另一个故事了。) - 工艺替代:
<(…)
创建一个子 shell,其标准输出设置为管道并扩展为管道的名称。父进程(或其他进程)可以打开管道与子 shell 进行通信。>(…)
执行相同的操作,但使用标准输入上的管道。 - 协同处理:
coproc …
创建一个子shell并且不等待它终止。子 shell 的标准输入和输出均设置为一个管道,父级连接到每个管道的另一端。
答案2
从 bash 版本 4.4 中的 bash(1) 手册页,“扩展”部分,“命令替换”小节:
command
Bash 通过在子 shell 环境中执行来执行扩展[...]
答案3
是的,( commands... )
是一个bash
将commands...
在另一个进程中执行的子 shell。
唯一的区别$( commands... )
是,这部分代码在执行后将被commands...
写入.commands...
stdout