Shell 脚本中如何使用 trap 命令捕捉和处理信号(中等)

👨‍⚕️ 主页: gis分享者

👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍⚕️ 收录于专栏:Shell 面试

文章目录

  • 一、🍀前言
    • [1.1 ☘️示例](#1.1 ☘️示例)
    • [1.2 ☘️使用语法](#1.2 ☘️使用语法)
    • [1.3 ☘️知识扩展](#1.3 ☘️知识扩展)

一、🍀前言

在 Shell 脚本中,我们可以使用 trap 命令来捕捉和处理特定的信号。这对于管理中断、清理临时文件或确保脚本终止时有适当的处理非常有用。

1.1 ☘️示例

trap 命令的基本格式是:

powershell 复制代码
trap 'commands' signals

其中:

  1. commands 是在捕捉到信号时要执行的命令。
  2. signals 是要捕捉的信号列表,多个信号可以用空格分隔。

一个常见的例子是捕捉 SIGINT 信号(通常是由 Ctrl-C 触发)来优雅地终止脚本:

powershell 复制代码
#!/bin/bash

# 捕捉 SIGINT 信号并执行 cleanup 函数
trap 'cleanup' SIGINT

cleanup() {
    echo "捕捉到 SIGINT 信号,正在清理临时文件..."
    # 在这里添加清理临时文件或其他资源释放的代码
    exit 0
}

echo "脚本正在运行,按 Ctrl-C 终止"
while true; do 
    sleep 1
done

1.2 ☘️使用语法

trap 命令基本语法

powershell 复制代码
trap 'command' SIGNAL

常用信号类型

  • SIGINT (2): 中断信号(Ctrl+C)
  • SIGTERM (15): 终止信号
  • SIGKILL (9): 强制终止信号(无法被捕获)
  • SIGUSR1 (10): 用户自定义信号1
  • SIGUSR2 (12): 用户自定义信号2
  • SIGQUIT (3): 退出信号(Ctrl+\)
  • SIGHUP (1): 挂起信号
  • EXIT (0): 脚本退出

基本用法示例

1. 捕捉 Ctrl+C 信号

powershell 复制代码
#!/bin/bash

# 捕捉 SIGINT 信号 (Ctrl+C)
trap 'echo "收到中断信号,正在退出..."; exit 1' SIGINT

echo "运行一个长时间任务..."
for i in {1..10}; do
    echo "处理中... $i"
    sleep 1
done

2. 捕捉脚本退出信号

powershell 复制代码
#!/bin/bash

# 捕捉脚本正常退出
trap 'echo "脚本执行完毕,清理资源..."' EXIT

echo "开始执行任务..."
sleep 2
echo "任务完成"
# 脚本结束时会自动触发 EXIT 信号处理

3. 捕捉多种信号

powershell 复制代码
#!/bin/bash

# 定义信号处理函数
cleanup() {
    echo
    echo "正在清理资源..."
    # 在这里添加清理代码
    rm -f /tmp/temp_file_$$
    echo "清理完成,退出程序"
    exit 0
}

# 捕捉多种信号
trap cleanup SIGINT SIGTERM SIGQUIT

# 创建临时文件
touch /tmp/temp_file_$$
echo "创建了临时文件 /tmp/temp_file_$$"

echo "运行中... 按 Ctrl+C 退出"
while true; do
    sleep 1
done

4. 信号处理函数示例

powershell 复制代码
#!/bin/bash

# 定义不同的信号处理函数
handle_sigint() {
    echo
    echo "捕获到 SIGINT 信号 (Ctrl+C)"
    echo "你可以选择:"
    echo "1) 继续执行"
    echo "2) 退出程序"
    read -p "请选择 (1/2): " choice
    case $choice in
        1) echo "继续执行...";;
        2) exit 0;;
        *) echo "无效选择";;
    esac
}

handle_sigterm() {
    echo
    echo "捕获到 SIGTERM 信号"
    echo "程序将在 3 秒后退出..."
    sleep 3
    exit 0
}

handle_exit() {
    echo "脚本正常退出,执行清理工作"
    # 清理临时文件等
}

# 设置信号处理器
trap handle_sigint SIGINT
trap handle_sigterm SIGTERM
trap handle_exit EXIT

# 主程序
echo "程序运行中,可以尝试发送信号"
echo "PID: $$"
for i in {1..100}; do
    echo "循环次数: $i"
    sleep 2
done

5. 高级用法:临时禁用和恢复信号处理

powershell 复制代码
#!/bin/bash

# 定义信号处理函数
signal_handler() {
    echo "信号处理函数被调用"
}

# 设置信号处理
trap signal_handler SIGINT

echo "信号处理已启用,PID: $$"
echo "现在可以按 Ctrl+C 测试"

sleep 5

# 临时禁用信号处理
trap '' SIGINT
echo "信号处理已禁用,Ctrl+C 将被忽略"
sleep 5

# 恢复信号处理
trap signal_handler SIGINT
echo "信号处理已恢复"
sleep 5

# 移除信号处理
trap - SIGINT
echo "信号处理已移除,使用默认行为"
sleep 5

6. 实用示例:带进度保存的长时间任务

powershell 复制代码
#!/bin/bash

# 任务进度文件
PROGRESS_FILE="/tmp/task_progress_$$"

# 清理函数
cleanup() {
    echo
    echo "接收到终止信号,保存进度..."
    echo "当前进度已保存到 $PROGRESS_FILE"
    echo "下次运行时可以从中断处继续"
    exit 0
}

# 设置信号处理器
trap cleanup SIGINT SIGTERM

# 初始化进度
if [ -f "$PROGRESS_FILE" ]; then
    progress=$(cat "$PROGRESS_FILE")
    echo "从进度 $progress 继续执行"
else
    progress=0
fi

# 模拟长时间任务
echo "开始执行任务,按 Ctrl+C 可以安全中断"
for i in $(seq $progress 100); do
    echo "进度: $i%"
    echo $i > "$PROGRESS_FILE"
    sleep 1
done

# 任务完成,清理进度文件
rm -f "$PROGRESS_FILE"
echo "任务完成"

trap 命令的其他用法

查看当前信号处理设置

powershell 复制代码
# 显示所有已设置的信号处理
trap -p

# 显示特定信号的处理设置
trap -p SIGINT

移除信号处理

powershell 复制代码
# 移除特定信号的处理
trap - SIGINT

# 移除所有信号处理
trap -

最佳实践

  • 使用函数处理复杂逻辑 - 将信号处理逻辑封装在函数中
  • 始终进行清理工作 - 在 EXIT 信号中清理临时文件和资源
  • 避免在信号处理函数中执行复杂操作 - 保持信号处理函数简单快速
  • 测试信号处理 - 确保信号处理按预期工作
  • 考虑信号的时机 - 注意信号可能在关键操作时到达
    通过合理使用 trap 命令,可以让 Shell 脚本更加健壮和用户友好,能够优雅地处理各种中断情况.

1.3 ☘️知识扩展

1. 常见信号

  • SIGINT (2): 发送中断信号(Ctrl-C)。
  • SIGTERM (15): 发送终止信号,默认的 kill 命令发送的信号。
  • SIGKILL (9): 强制终止,不可被捕捉或忽略。
  • SIGHUP (1): 发送挂起信号,通常在终端关闭时发送。

2. 使用 trap 清理临时文件: 我们可以在脚本运行时创建一些临时文件,而 trap 可以确保在脚本遇到中断时这些文件被及时清理:

powershell 复制代码
#!/bin/bash

tmpfile=$(mktemp)
echo "临时文件:$tmpfile"

trap 'rm -f $tmpfile; exit' INT TERM EXIT

# 模拟一些处理
echo "处理数据..." > "$tmpfile"
sleep 10

echo "处理完成"

3. 组合使用多个信号: 我们可以同时捕捉多种信号,并在处理过程中根据具体信号做不同处理:

powershell 复制代码
#!/bin/bash

trap 'echo "收到 SIGINT 信号"; exit 1' SIGINT
trap 'echo "收到 SIGTERM 信号"; exit 1' SIGTERM

echo "脚本开始运行..."
while true; do
    sleep 1
done

4. 高级用法:

捕捉多个信号并执行同一个命令:

powershell 复制代码
trap 'echo "捕获到信号"; cleanup' SIGINT SIGTERM

重置 trap 以处理默认行为:

powershell 复制代码
trap - SIGINT SIGTERM
相关推荐
Thanks_ks1 天前
【第 008 讲】在终端中运行 Python 程序:交互模式与脚本模式 | 绝对路径与相对路径 | 以模块方式运行 | 常见报错的识别与排查
python·异常处理·终端·脚本·命令行·cmd·python 解释器
谙弆悕博士2 天前
在文件夹右键直接打开 Kali WSL:一条 `wsl --cd` 注册表脚本
windows·脚本·wsl·右击·ksli
AnxiangLemon13 天前
Warp Lite :一个专注本地使用的开源终端
终端·shell·warp·warp lite
sbjdhjd16 天前
从污点追踪断点到 PHP-FPM 请求队列:HIDS PHP WebShell 样本复盘
开发语言·网络安全·数据挖掘·渗透测试·开源·php·shell
进击的荆棘18 天前
Linux系统——进程信号
linux·运维·服务器·信号
进击的荆棘18 天前
Linux系统——进程信号之保存和捕捉信号
linux·运维·服务器·信号处理·信号
Shell运维手记19 天前
Shell 结构化命令知识点总结(case、for、while)
运维·microsoft·shell·脚本
云计算练习生19 天前
什么是 Bash?Linux 默认 Shell 的核心功能
linux·操作系统·bash·shell·命令解释器
猫咪很可爱20 天前
MySQL 5.7 备份恢复后函数与存储过程丢失:原因分析与正确备份姿势
数据库·mysql·bug·shell
拂拉氏20 天前
【知识讲解】 Linux信号的认识与使用
linux·信号