从这链接 我得到以下有关 exec bash 内置命令的信息:
如果提供命令,则更换外壳无需创建新进程。
它到底是如何替代shell的(即它内部是如何工作的)?系统调用的工作方式是否exec*()
相同?
答案1
是的,内置函数最终使用了系统调用系列exec
之一。exec*()
正常运行命令也是如此。只是当你使用时exec
,它并没有先使用fork()
系统调用来创建新的进程,结果就是新的命令取代了shell。
答案2
我strace
在一个正在运行的bash
实例上做了一个。然后我调用了命令exec sleep 100
。现在看看发生了什么:
access("/bin/sleep", X_OK) = 0
...
execve("/bin/sleep", ["sleep", "100"], [/* 14 vars */]) = 0
...
nanosleep({100, 0},
...
exit_group(0) = ?
sleep
所以你可以看到,它几乎与你调用正常方式时发生的情况相同。bash
检查系统调用是否授予可执行权限( X_OK
) 。然后执行文件名指向的程序。系统调用之后,拥有对进程的控制权。它的事情:。它还保持相同的 pid。结束后该过程也结束。是否不再运行。/bin/sleep
access()
execve()
execve()
sleep
nanosleep()
sleep
sleep
bash
证据:
在另一个窗口中,我用 观看了整个过程ps
。在运行该命令之前,它看起来像这样:
$ ps -o stat,pid,cmd -p <pid>
Ss+ 10905 -bash
并在运行时:
$ ps -o stat,pid,cmd -p <pid>
Ss+ 10905 sleep 100
结束后sleep
该进程就消失了。
当我正常运行时发生了什么?
access("/bin/sleep", X_OK) = 0
...
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f6c9fd089d0) = 19261
...
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 19261
...
--- SIGCHLD (Child exited) @ 0 (0) ---
检查执行权限。然后创建一个子进程clone()
。该bash
实例现在位于后台进程组,sleep
现在位于前台进程组。最后,调用wait4()
等待子进程结束(需要 100 秒)。