透過登入後ssh
,我在中輸入以下命令bash
:
sleep 50000000000000 &
然後我是kill -9
該sleep
進程的父進程(即bash
)。然後終端機窗口同時斷開連線。
當我再次登入時,發現sleep
進程還活著。
問題: 為什麼sleep
我退出並關閉終端機後進程還能存活?在我看來,除了守護進程和nohup
程序之外的所有內容都將在註銷期間被殺死。如果sleep
這樣能活下來,是不是就代表我可以用這個方法來代替命令了nohup
呢?
答案1
太爾;博士:
sleep
為什麼我退出並關閉終端後進程還能存活?在我看來,除了守護進程和nohup
程序之外的所有內容都將在註銷期間被殺死。如果sleep
這樣能活下來,是不是就代表我可以用這個方法來代替命令了nohup
呢?
除非bash
所產生的實例設定ssh
了該huponexit
選項,否則在退出/登出時不會以任何方式終止任何進程,並且huponexit
設定該選項後,kill -9
在 shell 上使用並不是nohup
在 shell 子進程上使用的良好替代方案;nohup
在 shell 的子進程上仍然可以保護它們免受非來自 shell 的 SIGHUP 的影響,即使這並不重要,nohup
仍然是首選,因為它允許 shell 優雅地終止。
其中bash
有一個名為 的選項huponexit
,如果設定該選項,將bash
在退出/登出時使其子項 SIGHUP ;
在互動中未登入 bash
實例,例如在bash
由 產生的實例中gnome-terminal
,該選項將被忽略;無論huponexit
是設置或未設置,bash
的子級在bash
退出時都不會被 SIGHUPped;
在互動中登入 bash
實例,例如在bash
由 產生的實例中ssh
,不會忽略此選項(但預設未設定);如果huponexit
設定了,bash
則 的子層級將在bash
退出/登出時發出 SIGHUPped;如果huponexit
未設置,則 的子級在退出/登出時bash
不會發出 SIGHUPped ;bash
因此,一般來說,從互動式登入bash
實例退出/登出,除非huponexit
設定了該選項,否則不會使 shell 對其子級進行 SIGHUP,並且從互動式非登入bash
實例退出/登出也不會使shell對其子級進行SIGHUP不管;
然而,在這種情況下,這是無關緊要的:kill -9
sleep
無論如何,using 都會生存,因為殺死它的父進程 ( bash
) 不會給後者留下執行的機會任何事物到前者(即,例如,如果當前bash
實例是登入bash
實例並且huponexit
設定了該選項,則對其進行 SIGHUP)。
除此之外,與其他訊號(例如發送到 的 SIGHUP 訊號bash
)不同,SIGKILL 訊號永遠不會傳播到進程的子進程,因此sleep
甚至不會被終止;
nohup
啟動一個不受 SIGHUP 訊號影響的進程,這是不同的;它將防止進程在接收到 SIGHUP 訊號時掛起,在這種情況bash
下,如果huponexit
設定了選項並且 shell 退出,則互動式登入實例可以接收該訊號;因此從技術上講,使用未設定nohup
選項在互動式登入bash
實例中啟動進程huponexit
將防止進程在收到 SIGHUP 訊號時掛起,但登出/登出 shell 無論如何都不會 SIGHUP ;
然而,一般來說,當nohup
需要阻止來自父 shell 的 SIGHUP 訊號時,沒有理由更喜歡kill -9
on 父方法而不是nohup
on 子方法;相反,應該是相反的。
使用該方法殺死父進程kill -9
不會給父進程留下優雅退出的機會,而使用該nohup
方法啟動子進程允許父進程被其他信號終止,例如 SIGHUP (舉一個在上下文中有意義的例子的孩子開始使用nohup
),這允許它優雅地退出。
答案2
bash
預設情況下退出時不向子進程發送 HUP 訊號。更詳細(感謝@kos),它從來沒有這樣做過非登入 shell。
您可以配置 bash 來執行此操作登入外殼如果設定該選項huponexit
。在終端機中,執行以下操作:
[romano:~] % bash -l
(這將啟動一個新的「登入」外殼)
romano@pern:~$ shopt -s huponexit
romano@pern:~$ sleep 1234 &
[1] 32202
romano@pern:~$ exit
logout
現在檢查進程sleep
:
[romano:~] % ps augx | grep sleep
romano 32231 0.0 0.0 16000 2408 pts/11 S+ 15:23 0:00 grep sleep
……未運作:它已收到 HUP 訊號並按請求退出。
答案3
如果
sleep
能這樣生存下去,是否就代表我可以用這個方法來代替nohup
命令了?
kill -9
這確實不是一個人該走的路。這就像用槍射擊電視以將其關閉一樣。除了喜劇成分之外,沒有任何優勢。進程無法捕獲或忽略SIGKILL
。如果您不給進程機會完成正在執行的操作並進行清理,它可能會留下損壞的檔案(或其他狀態)並且無法重新啟動。kill -9
當其他方法都不起作用時,這是最後的希望。
為什麼當我註銷並關閉終端時睡眠進程可以存活。在我看來,註銷時除了守護程序和 nohup 程序之外的所有程序都會被殺死。
你的情況會發生什麼事:
的父進程sleep
是目前正在運行的bash
shell。當您kill -9
執行 bash 時,bash 進程沒有機會將 a 傳送SIGHUP
到其任何子進程,因為SIGKILL
(由 發送kill -9
)無法被該進程捕獲。睡眠進程繼續運作。睡眠現在變成了孤兒行程。
init (PID 1) 進程執行一種稱為 reparenting 的機制。這意味著 init 進程現在成為該孤立進程的父進程。 init 是一個例外,進程可以成為它的子進程,因為它收集丟失其原始父進程的進程。順便說一句:守護程式(如sshd
)在「進入背景」時會執行此操作。
如果這種情況沒有發生,孤立進程稍後(完成後)將成為殭屍進程。這就是waitpid()
未呼叫時發生的情況(父進程的責任在該進程被殺死時無法履行)。 initwaitpid()
在特定的時間間隔內呼叫以避免殭屍子程序。
答案4
使用&
將使程式作為背景運行。要在後台查看該程序,請使用bg
命令,並使其再次作為前台運行,請運行fg
。
是的,有很多方法可以讓程式在主終端退出時保持運作。