昨天有人建议我在 bash 中使用命令替换会导致生成不必要的子 shell。该建议具体针对这个用例 https://stackoverflow.com/q/21317997/313192:
# Extra subshell spawned
foo=$(command; echo $?)
# No extra subshell
command
foo=$?
据我所知,这对于这个用例来说似乎是正确的。然而,试图验证这一点的快速搜索会导致大量令人困惑和矛盾的建议。流行的观点似乎是,所有命令替换的使用都会产生一个子 shell。例如:
命令替换扩展到命令的输出。这些命令在子 shell 中执行,它们的标准输出数据是替换语法扩展到的内容。 (source http://wiki.bash-hackers.org/syntax/expansion/cmdsubst)
这看起来很简单,除非您继续挖掘,在这种情况下,您将开始找到对建议的引用,但事实并非如此。
命令替换不一定调用子shell,并且在大多数情况下不会。它唯一保证的是乱序求值:它只是先求值替换中的表达式,然后使用替换的结果求值周围的语句。 (source https://github.com/grncdr/js-shell-parse/issues/1)
这似乎很有道理,但事实果真如此吗?这个答案 https://stackoverflow.com/a/9109654/313192一个与子外壳相关的问题让我注意到man bash
有一点需要注意:
管道中的每个命令都作为单独的进程执行(即在子 shell 中)。
这让我想到了主要问题。到底是什么会导致命令替换产生一个无论如何也不会产生的子 shell 来单独执行相同的命令?
请考虑以下情况并解释哪些情况会产生额外子 shell 的开销:
# Case #1
command1
var=$(command1)
# Case #2
command1 | command2
var=$(command1 | command2)
# Case #3
command1 | command 2 ; var=$?
var=$(command1 | command2 ; echo $?)
这些对中的每一对都会产生相同数量的子 shell 来执行吗? POSIX 与 bash 实现有区别吗?是否存在其他情况,使用命令替换会生成子 shell,而单独运行同一组命令则不会?