我最近在阅读有关 linux 中的子 shell 的内容。使用的示例是 sleep 10。
(sleep 10) - subshell
sleep 10& - background process
coproc sleep 10
据记载,第一个命令在子 shell 中执行。第二种是不涉及子shell的后台进程。第三个是两者的结合。我已经使用测试过 ps -ef
,所有这些命令都显示了子 shell 的创建。使用 & 和 subshell 的后台进程有什么区别吗? coproc 似乎也在做同样的事情。我完全困惑了。任何有关该主题的说明将不胜感激。
答案1
在您的 shell 中,sleep
不是 shell 的内置命令,因此在任何情况下都必须在单独的进程中执行(这在内置命令中ksh93
或mksh
在sleep
内置命令中会有所不同)。
(sleep 10)
实现了一个子shell环境。这个想法是,对 shell 环境(别名、变量、函数、umask、工作目录、重定向...)进行的任何修改只会影响它,并在返回(...)
时丢失。(...)
在大多数 shell 中,这是通过分叉子进程来实现的。并非所有 shell 都这样做。ksh93
相反,将以前的环境设置保存在堆栈上并在退出时恢复它们,并且在这种情况下不会分叉。
在许多 shell 中,作为一种优化,如果子 shell 中的最后一个命令是外部命令(如sleep
您的情况),并且没有trap
设置,则 shell 不会分叉进程来运行它,而是直接在子 shell 中运行它过程,因为无论如何之后都不需要该过程。
对于 shell bash
,只有当该命令是子 shell 中的唯一命令时才会发生这种情况(这也是您的情况)。
sleep 10&
并且coproc sleep 10
还启动一个子 shell 环境,但在这些情况下,它们必须使用子进程来完成,因为您有两个并行执行的线程。两者之间的不同之处在于,在这种coproc
情况下,子 shell 的 stdin 和 stdout 连接到两个管道以与父 shell 交互。
与本(...)
例类似,如果子 shell 仅由一个命令组成,则该命令将直接在 shell 进程中执行。
为了更好地看到差异,您可能需要运行启动多个命令的子 shell,例如:
{ ps; echo done; } # no subshell
(ps; echo done)
{ ps; echo done; } &
coproc { ps; echo done; }