trap 命令详解

在 Shell 脚本编程中,trap 是一个非常关键的命令,它用于捕获信号(Signals)并执行预定义的命令

简单来说,它的作用是:当脚本被意外中断、报错或正常退出时,执行一些“善后工作”(比如清理临时文件、释放锁、打印日志)。


1. 为什么需要 trap

假设你的 Go 程序在运行过程中产生了一些临时文件(如 /tmp/go-build-xyz),或者你的脚本启动了一个后台进程。如果用户突然按下 Ctrl + C,或者脚本报错崩溃,这些临时文件就会留在硬盘里,后台进程也会变成“僵尸”。

使用 trap 可以确保:无论脚本如何结束,清理逻辑都会执行。


2. 基本语法

Bash

trap "要执行的命令" 信号名称
  • 信号名称

    • EXIT:脚本无论以何种方式退出(正常或意外)都会触发。

    • SIGINT:用户按下 Ctrl + C 时触发。

    • SIGTERM:系统请求终止进程时触发。

    • ERR:当某条命令执行失败(返回非 0 值)时触发。


3. 常见使用场景

A. 自动清理临时文件(最推荐)

这是编写健壮脚本的标配:

Bash

#!/bin/bash

# 创建一个临时文件
tmp_file=$(mktemp)
echo "正在处理数据..."

# 只要脚本退出,就执行 rm -f
trap "rm -f $tmp_file; echo '清理完成'" EXIT

# 这里模拟复杂的逻辑
sleep 10

B. 捕获 Ctrl + C 并优雅退出

如果你不想让用户随随便便中断脚本,或者想在中断前保存进度:

Bash

#!/bin/bash

trap "echo '别急,正在保存进度...'; exit" SIGINT

while true; do
    echo "后台运行中..."
    sleep 2
done

C. 报错时自动报警

如果脚本执行中途出错,立即通知你:

Bash

#!/bin/bash

trap "echo '警告:脚本在第 $LINENO 行执行失败!'" ERR

ls /non_existent_folder  # 这行会报错并触发 trap

4. 特殊用法:忽略信号

如果你正在执行一段极其重要、绝对不能被打断的代码(比如正在写入数据库或升级系统),可以暂时屏蔽信号:

Bash

trap "" SIGINT SIGTERM  # 捕获这些信号但不执行任何动作(即忽略)

# 重要操作开始
echo "正在写入关键数据,请勿中断..."
sleep 5
# 重要操作结束

trap - SIGINT SIGTERM  # 恢复信号的默认行为

5. 查看当前的 trap

你可以直接在终端输入 trap 来查看当前 Shell 环境中设置了哪些捕获。


6. 结合你目前服务器的实战

既然你在搞 Go 订阅系统,你可能会写一个 自动化编译并部署 的脚本:

Bash

#!/bin/bash

# 定义清理函数
cleanup() {
    echo "正在停止旧进程..."
    pkill my-go-app || true
}

# 脚本一旦运行失败或退出,就执行清理
trap cleanup EXIT ERR

echo "开始拉取代码并编译..."
go build -o my-go-app main.go

echo "启动程序..."
./my-go-app &

wait

💡 小贴士

  • EXIT 是万能的:大多数情况下,你只需要捕获 EXIT 信号,因为它涵盖了正常退出和被杀掉的情况。

  • 顺序很重要trap 必须写在可能报错的代码之前,否则信号还没捕获,脚本就崩了。

你现在是否有写一些 .sh 脚本来管理你的 Go 程序?我可以帮你优化一下,加入 trap 逻辑,让它更稳健。