为什么有些 Linux shell 脚本使用 exec 来运行命令?

Fra*_*ank 29 ubuntu shell-script

在 Linux bash 脚本中,例如:

exec /usr/lib/4.5/mono-service.exe ./AudioVideoRecorder.exe "$@"
Run Code Online (Sandbox Code Playgroud)

,为什么我必须exec执行命令而不是在没有exec零件的情况下运行它?

PSk*_*cik 35

简短的回答是:你没有,但它节省了大约 1毫秒的 CPU 时间(在现代 CPU 上)。(请注意,您应该exec只在脚本的末尾,因为exec将运行之后的任何内容)。

更长的答案是: Exec用您执行的可执行文件的进程映像替换当前进程的进程映像。这意味着在您执行 exec 的那一刻,执行execing的 shell 进程被完全破坏并被execed 程序取代。如果不这样做exec,shell 会分叉自己,在分叉中执行,并等待子进程退出,收集其返回状态,希望之后可能会运行其他命令(fork+exec是标准过程,其中产生新命令)。由于没有,这fork完全是在浪费时间,您不妨直接执行并节省该fork时间。

对于大多数意图和目的,它本质上是基于进程如何在 Unices 上产生的知识的微观优化。


注意:(感谢 ilkkachu)它产生轻微语义差异的地方是产生脚本的进程是否关心可能被执行的程序如何终止。如果可能被执行的子进程正常退出,则 exec 和非 exec 形式是等效的,因为 shell 脚本将最后等待的退出状态转发到它自己的退出状态。但是,如果孩子死于 signal n,那么 shell 会将其转换为 exit status 128+n,从而有效地丢失 was-signaled 信息。(如果您确定孩子从不经常使用退出代码退出,则信息不会丢失>128,通常是这种情况。)。当你执行 exec 时,不再有中间人 shell,退出状态信息直接发送给执行脚本的调用者(关于子进程是否退出或已发出信号的信息被保留,因为没有中间人 shell 将其合并到一个退出代码)。(有关更多信息,请参阅waitpid(2))。

  • 另外一个补充:`exec` 节省了一个 pid 和一些存储 shell 映像所需的少量内存(如果只剩下一个)和一些关于它的进程元数据,因为 shell 不存在并且不等待分叉进程完成。这在具有 16M 甚至 8M 板载 RAM 可用的嵌入式系统中可能至关重要。 (6认同)
  • 由于 exec 就地替换了 shell,它还使执行的程序成为 shell 父级的直接子级,而不是通过 shell 的孙子级。如果运行脚本的程序(以及最终执行的程序)关心它的孩子如何死亡,那可能很重要 (5认同)