Bash

為什麼我不能通過擊鍵終止從 Bash 腳本呼叫的超時?

  • June 10, 2019

$$ 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+CCtrl+殺死Z,但不能從腳本內部呼叫。

timeout 10 ping nowhere

…可以在bash 中使用Ctrl+CCtrl+殺死,並且在從腳本內部執行時使用+殺死。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

引用自:https://unix.stackexchange.com/questions/57667