從這連結 我得到以下有關 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 秒)。