每次我们ps
多次运行一个普通命令时,它都有不同的进程 ID (PID)。我想知道这是否意味着我们在终端(bash)中运行的每个命令都会创建一个 bash 子进程来执行该命令。
是的,几乎您在命令行上运行的每个命令都在其自己的进程中运行,并且这些进程是启动它们的 shell 的子进程。
这里的例外是 shell 的内置命令。Bash 本身实现了一些标准实用程序,例如printf
、echo
、true
、false
和kill
/ ,因此运行这些[
实用test
程序并不涉及分叉子项。这同样适用于诸如cd
、read
和 之类的东西mapfile
,尽管它们会影响 shell 的内部状态,因此它们必须是内置的。
(此外break
,continue
、 和return
,奇怪的是它们是内置实用程序,而不是像if
和 那样的 shell 关键字while
。)
shell 确实没有办法在与自身相同的进程中运行外部程序,同时仍然能够返回。然而,shell 可以用另一个程序替换自身。例如,如果您运行echo $$
查看 shell 的 PID,然后运行exec ps
,您将看到ps
使用相同的 PID 运行。当ps
退出时,该 shell 不再存在。fork()
实际上,每次以正常方式运行程序时都会发生类似的情况,只是 shell在用要运行的程序替换子程序 ( ) 之前复制自身(系统调用) execve()
。在子进程中运行的 shell 程序负责为子进程设置任何重定向等。
shell 也可以将其他工具实现为内置工具,例如 Busybox 实现是同一程序文件中较大的标准实用程序集。但据我测试,它在运行它们时仍然分叉一个子进程,可能是因为这是确保实用程序不会不必要地扰乱 shell 状态的简单方法。