4.2.5 信号发送与处理:kill、pkill、killall、trap

信号发送与处理:kill、pkill、killall、trap#

1. 原理概览(信号流转与处理)
- 信号是内核向进程发送的异步事件。
- 典型信号:SIGTERM(15)(请求退出)、SIGKILL(9)(强制终止)、SIGHUP(1)(重载/挂起)、SIGINT(2)(Ctrl+C)、SIGSTOP(19)(停止)、SIGCONT(18)(继续)。
- 优先使用可捕获的信号(如 SIGTERM),便于进程清理资源。

文章图片

2. kill:按 PID 发送信号(精准控制)
- 语法:kill [-signal] PID
- 命令解释:
- -15 或不写信号:发送 SIGTERM
- -9:发送 SIGKILL
- -1:发送 SIGHUP
- -l:列出所有信号

# 1) 观察目标进程
ps -ef | grep nginx

# 2) 优雅退出(推荐)
kill -15 1234

# 3) 强制终止(仅用于无响应进程)
kill -9 1234

# 4) 触发重载(如服务支持 SIGHUP)
kill -1 1234

# 5) 查看信号列表
kill -l

3. pkill:按名称/条件匹配进程(批量控制)
- 语法:pkill [-signal] pattern
- 常用参数说明:
- -f:匹配完整命令行
- -u:限制用户
- -n:最新一个进程

# 终止所有 nginx 进程(默认 SIGTERM)
pkill nginx

# 匹配命令行关键字,终止应用
pkill -f "java.*app.jar"

# 仅杀 www 用户的 nginx
pkill -u www -f nginx

# 仅终止最新启动的一个进程
pkill -n -f "python app.py"

4. killall:按进程名批量发送信号(名称严格匹配)
- 语法:killall [-signal] process_name
- 更适合单一服务的统一操作,避免 -f 误匹配。

# 优雅重载 nginx
killall -HUP nginx

# 强制终止 mysqld
killall -9 mysqld

5. trap:Shell 中捕获信号(清理与回滚)
- 语法:trap 'commands' SIGNAL
- 常用场景:清理临时文件、释放锁、优雅退出。

#!/bin/bash
# 文件:/opt/scripts/backup.sh

LOCK=/tmp/backup.lock
touch "$LOCK"

cleanup() {
  echo "清理资源..."
  rm -f "$LOCK"
  exit 0
}

# 捕获 SIGINT/SIGTERM,确保清理
trap 'cleanup' SIGINT SIGTERM

echo "开始备份..."
sleep 30
echo "备份完成"
cleanup
  • 取消捕获并恢复默认:
trap - SIGINT

6. 排错与验证(常见问题定位)
- 进程不退出:
- 可能忽略/捕获 SIGTERM,使用 strace -p PID 看是否响应。
- 误杀进程:
- pkill -f 匹配过宽,先用 pgrep -af pattern 验证。
- 无法重载:
- 服务不支持 SIGHUP,查看官方文档或日志确认。

# 先确认将要匹配的进程
pgrep -af "java.*app.jar"

# 跟踪进程对信号的反应
strace -p 1234 -e trace=signal

7. 练习与实操(可复制执行)
1) 启动一个可控测试进程:

sleep 600 &
echo $!  # 输出 PID

2) 发送不同信号并观察:

kill -15 <PID>   # 优雅退出
kill -9 <PID>    # 强制退出

3) 编写脚本测试 trap:

cat > /tmp/trap_test.sh <<'EOF'
#!/bin/bash
trap 'echo "收到 SIGINT,清理后退出"; exit 0' SIGINT
echo "运行中,按 Ctrl+C 触发..."
sleep 60
EOF
chmod +x /tmp/trap_test.sh
/tmp/trap_test.sh

4) 验证 pkill 的匹配范围:

pgrep -af "sleep 600"
pkill -f "sleep 600"