适用场景
巡检脚本经常需要先生成清单,再排序或统计。直接把中间结果写进固定文件名,多次运行容易互相覆盖,失败后也容易留下旧数据。本教程用一个小型排序任务演示:每次创建独立工作目录,正常结束或常见中断时清理自己的文件,同时保留原来的退出码。
适用于带 GNU Coreutils 和 Bash 的常见 Linux 系统。普通用户即可操作,建议先在练习目录完成,不需要管理员权限,也不修改系统配置。
原理
mktemp 会创建一个名称难以预测的实际文件或目录,而不是只给出一个候选名称。使用目录模式时,可以把本次运行的全部中间文件放到同一个私有空间。具体创建方式和权限说明见 GNU mktemp 官方文档。
Bash 的退出陷阱可以在 Shell 退出时执行清理函数。另为常见的中断、终止和挂断信号设置退出动作,就能让这些路径也进入统一清理。清理函数必须先保存原退出码,否则删除命令的执行结果可能掩盖业务失败。退出陷阱的语义见 Bash 官方手册。
本例只删除明确创建的两个文件,再尝试删除空目录。这样,即使以后误把其他文件放进工作目录,也会因为目录非空而保留现场,便于检查。
准备工作
在自己的练习目录中新建文本文件,命名为 temp-report-demo.sh。文件中不填写任何账号或敏感内容。下面使用的样例只有几行设备类型名称。
先确认所需工具存在:
command -v bash mktemp sort wc stat
正常情况下会列出各工具位置。缺少工具时,通过所在发行版的官方软件包渠道补齐,再继续操作。不要从不明网页复制安装脚本。
分步骤操作
第一步:保存完整脚本
将以下内容保存到 temp-report-demo.sh。work 是程序生成的目录路径,mode 是运行模式,均由脚本管理,不需要手工填写。临时目录的固定前缀只用于识别本示例,末尾的大写字母由 mktemp 替换。
#!/usr/bin/env bash
set -u
mode=${1:-normal}
case "$mode" in
normal|fail|wait) ;;
*) printf '用法:normal、fail 或 wait\n' >&2; exit 2 ;;
esac
work=$(mktemp -d /tmp/cnsz-temp-demo.XXXXXXXXXX) || exit 1
cleanup() {
result=$?
trap - EXIT
rm -f -- "$work/input.txt" "$work/sorted.txt"
if ! rmdir -- "$work"; then
printf '目录未完全清理,请检查:%s\n' "$work" >&2
fi
exit "$result"
}
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
trap 'exit 129' HUP
printf '临时目录:%s\n' "$work"
stat -c '目录权限:%a' -- "$work"
printf 'router\nswitch\nrouter\n' > "$work/input.txt" || exit 1
LC_ALL=C sort -u -- "$work/input.txt" > "$work/sorted.txt" || exit 1
if [[ "$mode" == fail ]]; then
printf '演示主动失败\n' >&2
exit 7
fi
if [[ "$mode" == wait ]]; then
printf '等待中,可按 Ctrl+C 中断\n'
while :; do
sleep 1
done
fi
printf '去重后条目数:'
wc -l < "$work/sorted.txt"
脚本没有使用递归删除,也没有清空整个临时目录。每次引用路径都加双引号,文件操作中的双连字符表示选项到此结束,避免路径被意外当成选项处理。
第二步:先检查语法
在保存脚本的目录执行:
bash -n ./temp-report-demo.sh
没有输出通常表示语法检查通过,但这并不代表业务逻辑已经验证。这里明确调用 Bash,避免其他 Shell 对脚本语法的支持差异。
第三步:检查正常完成与主动失败
分别运行两种模式,每条任务结束后立即读取退出码:
bash ./temp-report-demo.sh normal
printf '退出码:%s\n' "$?"
bash ./temp-report-demo.sh fail
printf '退出码:%s\n' "$?"
正常模式应报告两条去重结果,并返回零;失败模式应返回七。两次打印的临时目录路径应不同,证明各次运行使用了独立空间。目录权限通常显示七百,表示目录仅允许所有者访问。
第四步:验证中断路径
运行等待模式,看到提示后按 Ctrl+C:
bash ./temp-report-demo.sh wait
printf '退出码:%s\n' "$?"
该模式把中断退出码设为一百三十。Bash 等待前台命令时,陷阱执行可能要等命令返回,因此这里使用一秒短等待,不应把清理理解为任何情况下都瞬间完成。信号处理细节见 Bash Signals 文档。
验证方法
每次运行时记下脚本输出的完整临时目录路径,然后检查它是否还存在:
read -r -p '粘贴刚才的完整临时目录路径:' check_dir
if [[ -e "$check_dir" ]]; then
printf '路径仍存在,请检查清理提示\n'
else
printf '路径已不存在\n'
fi
check_dir 接收刚才输出的实际目录,不要填写公共临时目录本身。这个检查只读路径,不会删除内容。判断成功应同时满足:业务退出码符合预期、目录已消失、没有清理失败提示。
常见错误
只在脚本最后写删除命令,会漏掉中途退出的路径;使用固定文件名,则可能把上一次结果当成新结果。另一个错误是在清理函数执行完删除后才读取退出码,此时读到的已经是清理命令状态。
不要把独立脚本直接载入当前交互式 Shell,否则退出动作可能结束当前会话。也不要把重要报告仅保存在这个临时目录中;需要长期保留的最终成果,应在成功后明确写到事先规划的输出位置。
安全与回退
退出陷阱不能处理强制终止信号、突然断电或系统崩溃,因此不能承诺绝无残留。发现残留时,先确认没有脚本仍在使用该目录,再检查其中内容;不要按前缀批量删除未知目录。
本教程没有创建定时任务或修改服务,回退只需停止练习并删除保存的示例脚本。将模式扩展到真实任务前,应逐项列出临时文件,并保留清理失败提示,避免为了让目录消失而扩大删除范围。
参考资料与转载说明
本文依据上述公开资料进行中文原创整理,不是逐句翻译,也不替代厂商手册。操作前请核对自己的版本、型号和备份。
评论一下?