Will()构造总是启动一个子shell?

目前的shell

$ echo $$ 23173 

注意ps的父亲是当前shell

 $ ( ps -o pid,ppid,cmd ) PID PPID CMD 8952 23173 ps -o pid,ppid,cmd 23173 23169 bash 

但是在这里,ps的父母是子shell(bash)

 $ ( echo hello ; ps -o pid,ppid,cmd ) hello PID PPID CMD 8953 23173 bash 8954 8953 ps -o pid,ppid,cmd 23173 23169 bash 

bash是否正在进行优化? 如何得到一个额外的回声造成了差异,并在第三种情况下产生了一个子壳?

是的,你看到的是一个优化。 从技术上讲,按照定义, (…)构造总是启动一个子shell。 大多数情况下,子shell在一个单独的子进程中运行。 这可以确保子外壳中的所有内容都保留在子外壳中。 如果bash可以保证这个隔离属性,那么可以自由使用它喜欢的任何实现技术。

在片段( ps -o pid,ppid,cmd ) ,显然没有任何东西可以影响父shell,所以在bash中有一个优化,使得它不会为子shell分离一个单独的进程。 片段( echo hello ; ps -o pid,ppid,cmd )对于优化器来说太复杂了,以至于不需要使用子shell。

如果您尝试使用ksh ,您会注意到它的优化器更具侵略性。 例如,它不会为( echo hello ; ps -o pid,ppid,cmd )分叉一个子( echo hello ; ps -o pid,ppid,cmd )

一个由一个简单命令组成的子shell可以通过简单地“执行”命令来实现,而不是由多个命令组成的列表或管道,也就是说,用被调用的命令进程替换子shell。 如果subshel​​l更复杂,那么简单的exec是不可能的,subshel​​l必须留待管理命令序列。

从你的诊断中,不可能区分bash优化和简单命令组成的子shell优化到被调用的命令的“直接”分支和执行,或者子shell的分支,然后是被调用的命令的执行。 这是不足为奇的,因为差别几乎是完全学术的。