為什麼我不能通過擊鍵終止從 Bash 腳本呼叫的超時?
$$ Edit: This looks similar to some other questions asking how to kill all spawned processes – the answers all seem to be to use pkill. So the core of my question may be: Is there a way to propagate Ctrl-C/Z to all processes spawned by a script? $$
rec
當使用 coreutils中的timeout
命令(在此處討論)呼叫 SoX時,一旦從 Bash 腳本中呼叫它,似乎沒有任何方法可以通過擊鍵殺死它。例子:
timeout 10 rec test.wav
…可以用 bash 的
Ctrl
+C
或Ctrl
+殺死Z
,但不能從腳本內部呼叫。timeout 10 ping nowhere
…可以在bash 中使用
Ctrl
+C
或Ctrl
+殺死,並且在從腳本內部執行時使用+殺死。Z``Ctrl``Z
我可以找到程序 ID 並以這種方式殺死它,但為什麼我不能使用標準的中斷鍵擊?有什麼方法可以構造我的腳本以便我可以嗎?
Ctrl
+等信號鍵向前台程序組C
中的所有程序發送信號。在典型情況下,一個程序組是一個管道。例如,在 中
head <somefile | sort
,正在執行head
的程序和正在執行的程序sort
在同一個程序組中,shell 也是如此,所以它們都接收到信號。當您在後台 (somecommand &
) 執行作業時,該作業位於其自己的程序組中,因此按Ctrl
+C
不會影響它。該
timeout
程序將自己置於自己的程序組中。從原始碼:/* Ensure we're in our own group so all subprocesses can be killed. Note we don't just put the child in a separate group as then we would need to worry about foreground and background groups and propagating signals between them. */ setpgid (0, 0);
當發生超時時,
timeout
通過簡單的權宜之計殺死它所屬的程序組。由於它已將自己置於單獨的程序組中,因此其父程序將不在該組中。在此使用程序組可確保如果子應用程序分叉成多個程序,則其所有程序都將收到信號。當您
timeout
直接在命令行上執行並按Ctrl
+C
時,生成的 SIGINTtimeout
由子程序和由子程序接收,但不是由作為timeout
父程序的互動式 shell 接收。當timeout
從腳本呼叫時,只有執行腳本的 shell 接收到信號:timeout
沒有收到它,因為它在不同的程序組中。您可以使用內置命令在 shell 腳本中設置信號處理程序
trap
。不幸的是,事情並沒有那麼簡單。考慮一下:#!/bin/sh trap 'echo Interrupted at $(date)' INT date timeout 5 sleep 10 date
如果您在 2 秒後按
Ctrl
+C
,這仍會等待整整 5 秒,然後列印“中斷”消息。這是因為目前台作業處於活動狀態時,shell 不會執行陷阱程式碼。要解決此問題,請在後台執行作業。在信號處理程序中,呼叫
kill
以將信號中繼到timeout
程序組。#!/bin/sh trap 'kill -INT -$pid' INT timeout 5 sleep 10 & pid=$! wait $pid