為什麼 Ctrl-C 的行為與 kill -2 不同
我有一個應該處理 SIGINT 並正常關閉的程序。當我在沒有後台的情況下從終端執行這個程序時,我可以使用 Ctrl-C 很好地關閉它。檢查日誌顯示一切都按預期工作。
當我打開一個單獨的終端並打電話時
kill -2 [pid]
,kill -s INT [pid]
它什麼也不做。我在日誌中什麼也看不到,程序繼續照常執行,直到我在啟動它的終端中按下 Ctrl-C。Ctrl-C 如何發送信號和 kill 之間有什麼區別嗎?
額外細節:
有問題的程序是一個由 bash shell 腳本啟動的 Java 應用程序,該腳本設置了一些環境變數(即
CLASSPATH
),然後呼叫java [main class]
. 按下 Ctrl-Z 然後執行ps
會產生以下結果:$ ps -f UID PID PPID C STIME TTY TIME CMD mdeck 10251 10250 0 11:48 pts/2 00:00:00 -bash mdeck 13405 10251 0 18:12 pts/2 00:00:00 /bin/bash /usr/local/bin/myapp.sh mdeck 13509 13405 25 18:12 pts/2 00:00:03 java com.company.MyApp mdeck 13526 10251 0 18:13 pts/2 00:00:00 ps -f
Gilles 要求的 stty 輸出如下:
$ stty -a </dev/pts/2 speed 38400 baud; rows 40; columns 203; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
一種可能性是程序擷取了
Ctrl
+C
序列。檢查輸出stty -a
;該intr
設置指示哪個鍵組合(如果有)發送 SIGINT 信號,並isig
指示信號鍵是否已啟用(-isig
表示它們已禁用)。如果程序由多個程序組成,按
Ctrl
+C
將 SIGINT 發送到程序組中的所有程序。您可以通過將信號發送到程序組而不是將其發送到其中一個程序來獲得相同的效果。要向程序組發送信號,首先要確定其領導者:這是啟動所有其他程序的第一個程序;如果您在後台執行程序組,則顯示 PIDjobs -l
。程序組組長的PID是PGID(程序組id);將信號發送到其負極。例如,如果 PGID 為 1234,則執行kill -INT -1234
.如果程序由包裝腳本和主應用程序組成,則需要考慮兩種情況。如果沒有清理工作要做,以便包裝腳本在主應用程序終止時立即終止,請呼叫包裝腳本
exec
:#!/bin/sh export SOMEVAR=somevalue … exec /path/to/application "$@"
這樣,應用程序將替換腳本,繼承其 PID。一些 shell 優化了以執行另一個程序結束的腳本,但不是全部。當腳本需要執行一些清理(例如刪除臨時文件)時,這種方法不起作用。
考慮讓腳本檢測信號並將信號傳輸到應用程序。這是如何進行的草圖:
/path/to/application "$@" & app_pid=$! trap -INT 'kill -INT $app_pid' wait $! rm /temp/file