功能说明
脚本接收根目录参数,先校验目录存在且不是文件系统根,再枚举所有 .log 文件并打印。第二遍查找超过七天的 .tmp 文件,默认只显示将删除的路径,设置 APPLY=1 才真正删除。find 先用 -name .git -prune 排除版本库,-print0 让每个路径以 NUL 结尾,read -d ‘’ 按 NUL 读取,因此文件名里的空格、引号、换行都不会被拆分。
关键代码
while 循环通过进程替换 < <(find …) 运行,避免管道子 shell 导致计数器丢失,同时保持 NUL 分隔。printf %q 会把危险字符转义,便于观察实际文件名。删除使用 rm -f – “$file”,– 防止以短横线开头的文件名被当成选项。APPLY 只接受 0 或 1,root 为 / 时直接拒绝,降低误删风险。-mtime +7 基于修改时间,不包含正好七天的边界。
使用注意
find 的错误(例如权限不足)不会自动传播到 while 循环,生产脚本应把 find 输出到临时文件并检查退出状态。示例不跟随符号链接,避免跳出目标目录。-mtime 的粒度是天,且依赖文件系统时间戳。NUL 分隔不能直接用 grep 或 xargs 的默认模式处理,后续工具也要使用 -0。Bash 3.2 也支持 read -d ‘’,但某些极简环境可能缺少进程替换。
验证方式
创建包含空格、单引号、换行和以 - 开头的测试文件,分别运行 APPLY=0 与 APPLY=1,确认只删除 .tmp 且所有路径完整显示。把 root 设为 / 应被拒绝,把 APPLY 设为 2 应报错。可在仅有 .log 的目录运行,确认输出 no temporary files older than 7 days。
代码示例
#!/usr/bin/env bash
set -euo pipefail
root=${1:-.}
apply=${APPLY:-0}
if [[ ! -d "$root" ]]; then
printf 'not a directory: %s\n' "$root" >&2
exit 1
fi
if [[ "$root" == "/" ]]; then
printf 'refusing to scan the filesystem root\n' >&2
exit 1
fi
if [[ "$apply" != "0" && "$apply" != "1" ]]; then
printf 'APPLY must be 0 or 1, got %s\n' "$apply" >&2
exit 2
fi
printf 'log files (NUL-safe enumeration):\n'
while IFS= read -r -d '' file; do
printf ' %q\n' "$file"
done < <(
find "$root" \
-type d -name .git -prune -o \
-type f -name '*.log' -print0
)
found=0
while IFS= read -r -d '' file; do
found=$((found + 1))
if (( apply )); then
printf 'removing %q\n' "$file"
rm -f -- "$file"
else
printf 'would remove %q (set APPLY=1 to delete)\n' "$file"
fi
done < <(
find "$root" \
-type d -name .git -prune -o \
-type f -name '*.tmp' -mtime +7 -print0
)
if (( found == 0 )); then
printf 'no temporary files older than 7 days under %s\n' "$root"
fi