为什么 Ctrl-C 的行为与 kill -2 不同

Mik*_*eck 8 kill signals

我有一个程序应该处理 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 7

一种可能性是程序捕获了Ctrl+C序列。检查输出stty -a;该intr设置指示哪个组合键(如果有)发送 SIGINT 信号,并isig指示信号键是否启用(-isig意味着它们被禁用)。

如果程序由多个进程组成,按Ctrl+C将 SIGINT 发送到进程组中的所有进程。您可以通过将信号发送到进程组而不是将其发送到进程之一来获得相同的效果。要向进程组发送信号,首先要确定其领导者:这是启动所有其他进程的第一个进程;如果您在后台运行进程组,那就是jobs -l. 进程组长的PID为PGID(进程组id);将信号发送到其负极。例如,如果 PGID 是 1234,则运行kill -INT -1234.

如果程序由包装脚本和主应用程序组成,则需要考虑两种情况。如果没有清理工作要做,以便包装脚本在主应用程序终止时立即终止,请使包装脚本调用exec

#!/bin/sh
export SOMEVAR=somevalue
…
exec /path/to/application "$@"
Run Code Online (Sandbox Code Playgroud)

通过这种方式,应用程序替换脚本,继承其 PID。一些 shell 优化了以执行另一个程序结束的脚本,但不是全部。当脚本需要执行一些清理(例如删除临时文件)时,此方法不起作用。

考虑让脚本检测信号并将信号传输到应用程序。这是如何进行的草图:

/path/to/application "$@" &
app_pid=$!
trap -INT 'kill -INT $app_pid'
wait $!
rm /temp/file
Run Code Online (Sandbox Code Playgroud)