Shell Daily 2025-12-19: 優雅退場 (Trap)

寫腳本時,我們通常會在末尾寫上一句 rm /tmp/data_export.tmp 來清理現場。但如果腳本執行中途報錯退出了?或者用户不耐煩按了 Ctrl+C 強行終止?那行清理代碼永遠不會執行,垃圾文件就會日積月累。

要想寫出“死得體面”、不留垃圾的健壯腳本,你不能只關注開始,更要關注結束。這時你需要 trap

怎麼用

trap 命令允許你在腳本接收到特定信號(Signal)時,觸發預定義的操作。

  • 語法trap 'command_to_execute' SIGNAL_LIST
  • 兼容性POSIX 通用標準。所有主流 Shell 均支持。

適用場景

  • 清理臨時文件:無論腳本是正常結束還是被殺掉,確保刪除 /tmp 下的文件。
  • 釋放資源:刪除文件鎖 (Lock file) 或關閉後台起的子進程。
  • 回滾操作:如果部署腳本中斷,自動恢復之前的配置文件。

示例 1:全能的 EXIT 偽信號

這是最常用、價值最高的技巧。不同於 INT (Ctrl+C) 或 TERM (kill),EXIT 是一個 Shell 偽信號。無論腳本以何種方式結束(正常跑完、exit 1 報錯、被用户中斷),只要 Shell 進程退出,它都會觸發。

temp_file="/tmp/report_$(date +%s).csv"
touch "$temp_file"

# 註冊陷阱:腳本退出時,自動刪除臨時文件
trap 'rm -f "$temp_file"' EXIT

echo "Processing data..."
# 即使下面這行命令失敗導致腳本退出,或者你狂按 Ctrl+C
# rm 命令依然會被執行
sleep 10

示例 2:調用清理函數

如果清理工作很複雜,不要把代碼全塞在單引號裏,寫個函數更清晰:

pid_file="/var/run/my_daemon.pid"

cleanup() {
    echo "Cleaning up..."
    rm -f "$pid_file"
    # 還可以做更多,比如通知監控系統
    echo "Script stopped at $(date)"
}

# 註冊函數到 EXIT 信號
trap cleanup EXIT

echo $$ > "$pid_file"
# 模擬耗時任務
do_heavy_work