fish
我正在尝试调试我的 shell(特别是)向后台进程发送信号的问题。我希望能够识别进程正在接收什么信号。
理想情况下,我想要一些可以执行以下操作的程序:
$ log_signals > signals.txt &
然后将接收到的信号写入输出。然而,我不认为任何这样的程序已经存在。
捕获传入信号并检查它们的最简单方法是什么,最好不需要编写自己的程序?
(我运行的是 OS X,而不是 Linux,所以如果可能的话,我更喜欢一个与平台无关的答案。)
答案1
自从史蒂芬将此信息发布为评论,但我发现此信息比任何现有答案更有用,我将评论重新发布为答案。
仅适用于 Linux:strace
默认打印信号,因此您可以使用该-e
标志来静默所有系统调用,以便信号更清晰:
strace -e 'trace=!all' cmd
就我而言,我试图找出哪个进程正在杀死我正在运行的守护进程,所以我得到的输出如下所示:
[hendrenj@underling02 ~]$ strace -p 171869 -e 'trace=!all'
Process 171869 attached
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=151513, si_uid=1000} ---
+++ killed by SIGTERM +++
在这里您可以看到我附加到 PID 171869,并且该进程由 PID 151513 的进程发送了 SIGTERM。
如需进一步参考,您可以查看这篇博文,它建议使用诸如auditd
(我相信如果您使用的是使用 SELinux 的发行版的话,SELinux 附带的工具)或stap
(System Tap)之类的工具(如果strace
不够强大的话)。
答案2
我意识到您可以直接连接trap
命令来检测任何信号,而不是有一些依赖性。下面的脚本在信号上设置了一些“陷阱”(当相关信号进入时执行一个函数),然后将信号作为退出代码输出。如果您愿意,可以将退出更改为控制台输出。
#!/bin/sh
trap cleanup_1 1 # SIGHUP
trap cleanup_2 2 # SIGINT
trap cleanup_3 3 # SIGQUIT
trap cleanup_6 6 # SIGABRT
trap cleanup_15 15 # SIGTERM
cleanup_1()
{
exit 1
}
cleanup_2()
{
exit 2
}
cleanup_3()
{
exit 3
}
cleanup_6()
{
exit 6
}
cleanup_15()
{
exit 15
}
echo "Started"
cat
答案3
您可以使用gdb
以下方法来执行此操作:
gdb --batch -ex 'handle all print' -ex 'handle all nostop' -ex 'handle all pass' -ex 'run' cat
将在 GDB 下运行 cat 并打印所有信号,将它们传递给程序而不停止执行。
对后台程序执行此操作比较困难,因为 GDB 会尝试进入后台。您可能最好使用 启动它cat &
,然后将调试器附加到另一个窗口中:gdb -ex 'handle all print' -ex 'handle all nostop' -ex 'handle all pass' -ex 'c' (pgrep cat)[1]
。按q[ENTER]
三下即可通过所有垃圾,然后您就可以观看cat
跑步了。
答案4
strace -o logfile -e signal=all cmdline