互動式 shell 應該在孤立的程序組中做什麼?
(根據https://stackoverflow.com/questions/13718394/what-should-interactive-shells-do-in-orphaned-process-groups中的建議在 unix 中重新發布)
簡短的問題是,如果 shell 位於不擁有 tty 的孤立程序組中,它應該做什麼?但我建議閱讀長問題,因為它很有趣。
這是一種有趣且令人興奮的方法,可以使用您最喜歡的外殼將您的筆記型電腦變成攜帶式空間加熱器(除非您是那些 tcsh 怪人之一):
#include <unistd.h> int main(void) { if (fork() == 0) { execl("/bin/bash", "/bin/bash", NULL); } return 0; }
這會導致 bash 將 CPU 固定在 100%。zsh 和 fish 也一樣,而 ksh 和 tcsh 咕噥著一些關於工作控制的事情,然後就倒下了,這有點好,但不多。哦,這是一個與平台無關的違規者:OS X 和 Linux 都受到影響。
我的(可能是錯誤的)解釋如下:子外殼檢測到它不在前台:
tcgetpgrp(0) != getpgrp()
. 因此它試圖停止自己:killpg(getpgrp(), SIGTTIN)
. 但是它的程序組是孤立的,因為它的父程序(C 程序)是領導者並且死了,並且SIGTTIN
發送到孤立的程序組只是被丟棄(否則沒有什麼可以再次啟動它)。因此,子 shell 並沒有停止,但它仍然在後台,所以它會立即再次執行所有操作。沖洗並重複。我的問題是,命令行 shell 如何檢測到這種情況,它應該做什麼?我有兩個解決方案,都不是理想的:
- 嘗試向 pid 與我們的組 ID 匹配的程序發出信號。如果失敗
ESRCH
,則意味著我們可能是孤兒。- 嘗試從
/dev/tty
. 如果失敗EIO
,則意味著我們可能是孤兒。(我們跟踪的問題是https://github.com/fish-shell/fish-shell/issues/422)
謝謝你的想法!
我同意你的分析,我同意聽起來你必須檢測你的程序組是否是孤立的。
tcsetattr
如果程序組是孤立的,也意味著返回EIO
(並且我們沒有阻止/忽略 SIGTT OU。這可能比read
終端上的 a 侵入性更小。請注意,您可以使用以下方法重現它:
(bash<&1 &)
您需要重定向,否則在後台執行命令時標準輸入將重定向到 /dev/null。
(bash<&1 & sleep 2)
給出更奇怪的行為,因為你最終會從終端讀取兩個 shell。他們忽略
SIGTTIN
並且新的沒有檢測到,一旦啟動它就不再在前台程序組中。
ksh93
的解決方案還不錯:在放棄之前只能通過該循環最多 20 次(而不是無限次)。