Shell 脚本运行过程中可能创建临时文件、锁文件、后台进程或外部资源。如果脚本被手动终止或异常退出,这些资源可能残留。处理思路是:把清理逻辑统一写进 cleanup 函数,并通过 trap 在脚本退出时执行。
建议使用 trap 'cleanup' EXIT 作为统一清理入口。需要在收到 TERM、INT、HUP 时做额外处理的,可以单独捕获信号,然后退出脚本,让 EXIT trap 执行清理。
下面是通用骨架,已包含临时目录和后台进程的清理示例;若脚本创建了其他资源(如锁文件、挂载点、远端资源等),请在 cleanup 中补齐相应清理逻辑。
#!/usr/bin/env bash set -euo pipefail TMP_DIR="" CHILD_PID="" cleanup() { # 清理过程失败时,不要影响后续清理 set +e # 终止后台子进程 if [[ -n "${CHILD_PID}" ]]; then kill -TERM "${CHILD_PID}" 2>/dev/null || true fi # 删除脚本创建的临时目录 if [[ -n "${TMP_DIR}" && -d "${TMP_DIR}" ]]; then rm -rf -- "${TMP_DIR}" || true fi } on_signal() { local sig="$1" echo "received ${sig}, exiting..." >&2 exit 1 } # 脚本退出时统一清理 trap 'cleanup' EXIT # 可选:收到终止信号后退出,触发 EXIT 清理 trap 'on_signal TERM' TERM trap 'on_signal INT' INT trap 'on_signal HUP' HUP # 创建资源后及时记录 TMP_DIR="$(mktemp -d /tmp/myjob.XXXXXX)" # 示例:启动后台任务 # long_running_task & # CHILD_PID=$! # ...业务逻辑...
trap 会覆盖之前的清理逻辑,建议只在脚本开头统一注册一次。TERM/INT/HUP 后如果不调用 exit,信号相当于被“消化”,脚本会继续运行,收到信号本该触发的清理也不会立即发生。kill -9。该信号无法捕获,属于预期外场景。资源无法清理的情况主要有以下两种:
kill -9、机器意外重启或断电、进程被系统强制回收等,清理逻辑没有机会执行。建议做法:对外部资源额外提供兜底清理机制,例如定期运行清理脚本,或在必要时进行人工清理。如果条件允许,可给外部资源设置统一命名或标签,并配置 TTL,方便定期清理脚本按规则回收。