我想删除$DIR_TO_CLEAN
中早于$DAYS_TO_SAVE
天的文件。简单:
find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec rm {} ;
我想我们可以为rm
添加一个-type f
或-f
标志,但我真的想统计被删除的文件数量。
我们可以天真地这样做:
DELETE_COUNT=`find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE | wc -l`
find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec rm {} ;
但这个解决方案还有很多不足之处。除了命令重复之外,如果rm
未能删除文件,此代码段还会高估计数。
我对重定向、管道(包括命名管道)、子外壳、xargs
、tee
等都很满意,但我渴望学习新技巧。我想要一个同时适用于bash和ksh的解决方案。
如何计算find
删除的文件数
我会避开-exec
,选择管道解决方案:
find "$DIR_TO_CLEAN" -type f -mtime +$DAYS_TO_SAVE -print0
| awk -v RS=' ' -v ORS=' ' '{ print } END { print NR }'
| xargs -0 rm
使用awk
对匹配进行计数并将其传递给rm
。
更新:
kojiro让我意识到上述解决方案不计算rm
的成功/失败率。由于awk
存在名称不正确的文件问题,我认为以下bash
解决方案可能更好:
find "${DIR_TO_CLEAN?}" -type f -mtime +${DAYS_TO_SAVE?} -print0 |
(
success=0 fail=0
while read -rd $' ' file; do
if rm "$file" 2> /dev/null; then
(( success++ ))
else
(( fail++ ))
fi
done
echo $success $fail
)
您可以在find:中使用bash
find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec bash -c 'printf "Total: %dn" $#; rm "$@"' _ {} +
当然,如果找到的文件数大于MAX_ARGS,它可以多次调用bash -c …
,如果rm失败,它也可能高估计数。但解决这些问题会变得一团糟:
find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec bash -c 'printf "count=0; for f; do rm "$f" && (( count++ )); done; printf "Total: %dn" $count' _ {} +
这种避免MAX_ARGS限制的解决方案完全避免了查找。如果你需要它是递归的,你就必须使用递归globbing,它只在更新的shell中可用。(globstar
是bash4功能。)
shopt -s globstar
# Assume DAYS_TO_SAVE reformatted to how touch -m expects it. (Exercise for the reader.)
touch -m "$DAYS_TO_SAVE" referencefile
count=0
for file in "$DIR_TO_CLEAN/"**/*; do
if [[ referencefile -nt "$file" ]]; then
rm "$file" && (( count++ ))
fi
done
printf 'Total: %dn' "$count"
这里有一种将find与printf结合使用的方法(严格兼容的find没有printf,但在这种情况下,您可以将printf作为一个独立的实用程序使用)。
find "$DIR_TO_CLEAN" -type -f -mtime "+$DAYS_TO_SAVE" -exec rm {} ; -printf '.' | wc -c
find "$DIR_TO_CLEAN" -type -f -mtime "+$DAYS_TO_SAVE" -exec rm {} ; -exec printf '.' ; | wc -c