Linux ()构造是否总是启动子shell?

Linux ()构造是否总是启动子shell?,linux,bash,shell,Linux,Bash,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) bash正在进行优化吗?为什么在第三种情况下,一个额外的echo产生了不同的结果并产生了一个子shell?一个由单个简单命令组成的子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)


bash正在进行优化吗?为什么在第三种情况下,一个额外的echo产生了不同的结果并产生了一个子shell?

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


从您的诊断中,不可能区分bash优化(其中由简单命令组成的子shell优化为被调用命令的“直接”fork和exec)与子shell fork后跟被调用命令的exec)之间的区别。这并不奇怪,因为差异(几乎?)完全是学术性的。

是的,您看到的是优化。从技术上讲,
(…)
构造根据定义总是启动子shell。大多数情况下,子shell在单独的子进程中运行。这确保在子shell中完成的所有操作都留在子shell中。如果bash能够保证这个隔离属性,那么就可以自由地使用它喜欢的任何实现技术

在片段
(ps-opid,ppid,cmd)
中,很明显没有任何东西可以影响父shell,因此bash中有一个优化,使它不会为子shell派生单独的进程。片段
(echo hello;ps-o pid,ppid,cmd)
太复杂,优化器无法识别不需要子shell


如果您尝试使用
ksh
,您会注意到它的优化器更具攻击性。例如,它也不会为
(echo hello;ps-o pid,ppid,cmd)
派生子流程。

热门提示:您可以使用
ps-H
获得一个流程树,它可以让您更清楚地看到正在发生的事情,而不必自己连接pid和ppid。(但这并没有改变根本的问题,只是让它更容易理解。)要做更好的分析,最好选择$BASHPID而不是$$Note,如果您想要分组而不使用子shell,请使用
{方括号;}
。但是,它们需要一些额外的语法(空格、分号)。在bash impl代码中,您是否有一个链接来说明优化器是如何决定放弃的?我看到类似的行为
(…)
语法。还有
{…;}
语法。有时可以避免使用中间子shell,但在这种情况下,我觉得实现依赖于此。或者,是否正式记录了优化行为?@Hakan查看源代码。它没有文档记录,并且因版本而异。
$ ( echo hello ; ps -o pid,ppid,cmd )
hello
  PID  PPID CMD
 8953 23173 bash
 8954  8953 ps -o pid,ppid,cmd
23173 23169 bash