Shell:临时目录配 trap,脚本退出时顺手清理

34 次浏览4 条回复

写 Bash 小脚本时,如果中间要落几个临时文件,我一般会把 mktemp -d 和 trap 放一起用,脚本正常结束或报错退出时都能清一下。

环境:bash 4+,Linux/macOS 都能试。新建 tmp-clean.sh:

#!/usr/bin/env bash
set -euo pipefail

tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

printf 'hello temp\n' > "$tmpdir/data.txt"
cat "$tmpdir/data.txt"

echo "临时目录在脚本里存在:$tmpdir"

运行:

bash tmp-clean.sh

这个写法适合本地一次性处理文件。要注意 rm -rf 前面的变量一定要来自 mktemp -d 这种可控结果,别拿用户输入直接拼进去。

这个写法挺适合小脚本。

我一般还会把清理函数拆出来一点点,主要是以后想加日志或者判断时不挤在一行里:

cleanup() {
  [[ -n "${tmpdir:-}" && -d "$tmpdir" ]] && rm -rf "$tmpdir"
}
trap cleanup EXIT

mktemp -d 如果失败,配合 set -e 会直接退;上面这个 ${tmpdir:-} 也能避免变量没赋值时清理函数自己再炸一次。

NiroLv1#1

这个写法挺适合小脚本。

我一般还会把清理函数拆出来一点点,主要是以后想加日志或者判断时不挤在一行里:

cleanup() {
  [[ -n "${tmpdir:-}" && -d "$tmpdir" ]] && rm -rf "$tmpdir"
}
trap cleanup EXIT

mktemp -d 如果失败,配合 set -e 会直接退;上面这个 ${tmpdir:-} 也能避免变量没赋值时清理函数自己再炸一次。

这个拆成函数更稳,后面加日志也方便。再补一个容易忽略的点:EXIT 只保证 shell 能正常收尾时执行,SIGKILL 或机器断电这类情况没法清理。要处理 Ctrl-C / TERM 的话,可以让信号先退出,再统一交给 EXIT:

trap 'exit 130' INT TERM
trap cleanup EXIT

这样不会把清理逻辑复制两份,cleanup 本身也保持幂等就好。

还有个小习惯也挺好用:调脚本时先留一个开关,出问题就别立刻删临时目录,方便回头看中间文件。

keep_tmp=${KEEP_TMP:-0}
cleanup() {
  if [[ "$keep_tmp" == 1 ]]; then
    echo "keep tmpdir: $tmpdir" >&2
    return
  fi
  rm -rf "$tmpdir"
}
trap cleanup EXIT

平时直接跑会清理;需要排查时用 KEEP_TMP=1 bash tmp-clean.sh。这种比临时注释掉 trap 稍微稳一点,不容易改完忘了改回去。

再补个偏实用的小点:临时目录里如果会放 token、cookie 这类敏感配置,脚本开头可以顺手收一下权限,别让同机器其他用户读到。

umask 077
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

mktemp -d 建出来的目录一般已经比较保守,但 umask 077 能顺便管住后面新建的文件。服务器上跑一次性脚本时我会更倾向这么写。