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
相关推荐
課代表17 小时前
bat 批处理中 FOR 命令的变量修饰符
脚本·bat·环境变量·批处理·路径·扩展名·短名称
IT 乔峰1 天前
脚本部署MHA集群
linux·shell
課代表2 天前
PowerShell 目录树生成与递归算法陷阱:目录统计为何从0变多?
脚本·powershell·bat·目录·计数·文件夹·树状结构
牛奶咖啡134 天前
shell脚本编程(一)
linux·shell·shell脚本·shell脚本解析·grep命令语法·grep选项详解·正则表达式解析
gis分享者6 天前
请解释 Shell 脚本中的重定向(redirection)操作及其用途(中等)
shell·脚本·重定向·操作·用途·redirection
我是koten6 天前
K8s启动pod失败,日志报非法的Jar包排查思路(Invalid or corrupt jarfile /app/xxxx,jar)
java·docker·容器·kubernetes·bash·jar·shell
lingxiao168887 天前
vs脚本自动复制生成的文件至指定的位置
c#·脚本
我在人间贩卖青春8 天前
进程信号机制
进程·信号·进程信号
Huazzi.8 天前
PowerShell 配置以及使用指南
windows·git·编辑器·shell·powershell·效率