Appearance
信号处理
信号(Signal)是 Linux 进程间通信的一种机制,用于通知进程发生了某个事件。
常见信号
| 信号 | 编号 | 说明 |
|---|---|---|
SIGHUP | 1 | 挂起(终端关闭) |
SIGINT | 2 | 中断(Ctrl+C) |
SIGQUIT | 3 | 退出(Ctrl+\) |
SIGKILL | 9 | 强制终止(不可捕获) |
SIGTERM | 15 | 终止(默认 kill 信号) |
SIGSTOP | 17 | 暂停进程(不可捕获) |
SIGCONT | 18 | 继续运行 |
SIGCHLD | 17 | 子进程状态改变 |
SIGUSR1 | 10 | 用户自定义信号 1 |
SIGUSR2 | 12 | 用户自定义信号 2 |
bash
# 查看所有信号
kill -l发送信号
bash
# 使用 kill 发送信号(默认 SIGTERM)
kill PID
kill -15 PID
kill -TERM PID
# 强制终止进程
kill -9 PID
kill -KILL PID
# 发送给进程组
kill -TERM -PID
# 按名称发送(杀死所有同名进程)
killall process_name
killall -9 nginx
# 更精确的名称匹配
pkill process_name
pkill -f "python script.py" # 匹配完整命令行捕获信号(trap)
trap 命令用于在 Shell 脚本中捕获信号并执行自定义处理:
bash
# 基本语法
trap '命令' 信号列表
trap '函数名' 信号列表捕获 Ctrl+C(SIGINT)
bash
#!/bin/bash
trap 'echo "捕获到 Ctrl+C,正在退出..."; exit 1' INT
echo "按 Ctrl+C 测试信号捕获"
while true; do
echo "运行中..."
sleep 2
done清理临时文件
bash
#!/bin/bash
TEMP_FILE="/tmp/myapp_$$.tmp"
# 注册清理函数
cleanup() {
echo "清理临时文件..."
rm -f "$TEMP_FILE"
exit 0
}
trap cleanup EXIT INT TERM
# 创建临时文件
echo "临时数据" > "$TEMP_FILE"
echo "脚本运行中,按 Ctrl+C 退出"
sleep 30忽略信号
bash
#!/bin/bash
# 忽略 SIGHUP(终端断开时不退出)
trap '' HUP
echo "此脚本不会因终端关闭而退出"
sleep 60恢复默认信号处理
bash
#!/bin/bash
trap 'echo "收到信号"' INT
# 恢复默认处理(不再捕获)
trap - INT
sleep 10 # 此时 Ctrl+C 将正常终止脚本多信号处理
bash
#!/bin/bash
handle_int() {
echo "收到 SIGINT,优雅退出"
exit 130
}
handle_term() {
echo "收到 SIGTERM,执行清理"
# 执行清理操作
exit 0
}
handle_usr1() {
echo "收到 SIGUSR1,重新加载配置"
# 重新加载逻辑
}
trap handle_int INT
trap handle_term TERM
trap handle_usr1 USR1
echo "PID: $$,等待信号..."
while true; do
sleep 1
done常用 trap 模式
EXIT 钩子(脚本退出时必定执行)
bash
#!/bin/bash
on_exit() {
local exit_code=$?
echo "脚本退出,退出码:$exit_code"
# 清理资源
rm -f /tmp/lock_$$
}
trap on_exit EXIT
# 正常或异常退出都会触发 on_exit
echo "正在执行..."
exit 0防止重复运行(锁文件 + 信号)
bash
#!/bin/bash
LOCK_FILE="/tmp/myapp.lock"
if [ -f "$LOCK_FILE" ]; then
echo "脚本已在运行,退出"
exit 1
fi
touch "$LOCK_FILE"
trap 'rm -f "$LOCK_FILE"' EXIT INT TERM
echo "脚本开始运行,PID: $$"
sleep 30向进程发送 SIGUSR1 实现通信
bash
#!/bin/bash
# 守护进程示例:接收 SIGUSR1 重新加载配置
CONFIG_FILE="/etc/myapp.conf"
reload_config() {
echo "$(date): 重新加载配置 $CONFIG_FILE"
}
trap reload_config USR1
echo "守护进程 PID: $$"
while true; do
sleep 1
done
# 另一个终端执行:kill -USR1 <PID> 触发重载