如何排查复杂脚本中子脚本执行被终止的发起者?
这事儿确实挺闹心的——跑6小时的长脚本突然丢了1-2个子进程,就一句“脚本已被终止”,连谁干的都不知道。别担心,要揪出这个“终止发起者”完全可行,给你几个实用的方向:
Linux下的auditd是专门干这个的,它能记录所有关键系统调用,包括发送终止信号的操作:
- 先确保
auditd已安装并启动:sudo systemctl start auditd - 添加监控信号发送操作的规则:
这条规则会标记所有64位系统上的信号发送行为,方便后续精准查询。sudo auditctl -a exit,always -F arch=b64 -S kill -S tkill -S tgkill -k track_kills - 子脚本被终止后,用
ausearch提取相关日志:
日志里会明确显示发送信号的进程PID、所属用户,甚至执行的具体命令(比如是谁用sudo ausearch -k track_kills | grep -A 10 -B 5 "<子脚本PID>"kill命令终止了进程)。
虽然强制终止信号SIGKILL没法被捕获,但SIGTERM、SIGINT这类常见的终止信号是可以拦截的。我们可以在子脚本开头加一段代码,收到信号时自动记录关键信息:
#!/bin/bash # 定义信号处理函数 handle_term() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] 子脚本 $$ 收到终止信号!" >> /var/log/subscript_kill.log echo "发送信号的父进程信息:" >> /var/log/subscript_kill.log ps -o pid,ppid,user,cmd -p $(ps -o ppid= -p $$) >> /var/log/subscript_kill.log echo "当前登录用户列表:" >> /var/log/subscript_kill.log who >> /var/log/subscript_kill.log exit 1 } # 绑定信号处理逻辑到常见终止信号 trap handle_term SIGTERM SIGINT SIGHUP # 子脚本原有业务逻辑...
如果是被SIGKILL干掉的,这个方法抓不到,但至少能覆盖大部分用户手动终止或其他脚本发送的“友好”终止信号场景。
strace可以跟踪进程的所有系统调用,我们可以只过滤信号相关的内容,避免生成过大的日志:
- 启动子脚本时附加strace追踪:
strace -e signal -o /var/log/subscript_strace_$$.txt ./your_subscript.sh &-e signal参数会让日志只记录信号相关的调用,大幅缩小日志体积。 - 子脚本终止后查看日志,会看到类似这样的记录:
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=1234, si_uid=1000} ---
这里的si_pid=1234就是发送信号的进程ID,si_uid=1000是对应的用户ID,用id 1000就能查到用户名,ps -p 1234可查看进程详情。
有时候不是人为终止,是系统内存不足时,Linux的OOM Killer会自动杀掉占用内存较高的进程。这时候可以查dmesg日志确认:
dmesg | grep -i "out of memory"
如果看到类似Out of memory: Killed process 5678 (your_subscript.sh)的记录,那就是系统自动终止的,而非人为操作。
总的来说,只要结合系统级审计、子脚本监控和工具追踪,完全可以定位到终止子脚本的发起者。
内容的提问来源于stack exchange,提问作者Bobby

