Bash 使用Unix查找计数并删除旧文件

Bash 使用Unix查找计数并删除旧文件,bash,unix,ksh,Bash,Unix,Ksh,我想删除$DIR\u to\u CLEAN中早于$DAYS\u to\u SAVEDAYS的文件。简单: 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" -

我想删除
$DIR\u to\u CLEAN
中早于
$DAYS\u to\u SAVE
DAYS的文件。简单:

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
删除文件失败,此代码段还会高估计数

我对重定向、管道(包括命名的管道)、子shell、
xargs
tee
等非常熟悉,但我渴望学习新技巧。我想要一个同时适用于bash和ksh的解决方案


如何计算被
find
删除的文件数?

您可以在find中使用bash:

find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec bash -c 'printf "Total: %d\n" $#; 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: %d\n" $count' _ {} +
这种避免最大参数限制的解决方案完全避免了查找。如果您需要它是递归的,那么您必须使用递归全局绑定,这只在较新的shell中可用。(
globstar
是bash4的一项功能。)

这里有一种将find与printf结合使用的方法(严格兼容的find没有printf,但在这种情况下,您可以将printf作为一个独立的实用程序使用)


我会避免使用
-exec
,而选择管道式解决方案:

find "$DIR_TO_CLEAN" -type f -mtime +$DAYS_TO_SAVE -print0 \
| awk -v RS='\0' -v ORS='\0' '{ print } END { print NR }'  \
| xargs -0 rm
使用
awk
对匹配项进行计数并将其传递给
rm

更新: kojiro让我意识到上述解决方案不包括
rm
的成功/失败率。由于
awk
存在名称不正确的文件问题,我认为以下
bash
解决方案可能更好:

查找“${DIR\u TO_CLEAN?}”-键入f-mtime+${DAYS\u TO_SAVE?}-print0|
(
成功=0失败=0
读取-rd$'\0'文件时;执行以下操作
如果rm“$file”2>/dev/null;则
((success++)
其他的
((失败++))
fi
完成
echo$success$fail
)

否的可能重复,这不是重复。另一个问题并没有询问或解决当
-exec
ed命令失败时计数会发生什么情况。我喜欢一个好的单行程序,但我将继续循环,可能是通过管道将
find
导入其中。应该是继我之后的任何人最容易维护的,避免了最大参数问题,并允许轻松访问
rm
返回代码。谢谢大家!@Prashant不使用管道查找,这很危险:如果您的文件名中有新行怎么办?
在读取文件时查找“$DIR_TO_CLEAN”-mtime+$DAYS_TO_SAVE;执行rm“$FILE”;完成
引用“$FILE”只处理空格,不处理换行符?啊,我已经测试过了,现在明白你关于换行符的观点了,小二郎。谢谢你的洞察力。我后来为任何读者找到了一个。这个答案将计算
rm
未能删除的文件。另外,作为一种边缘情况,
xargs
受MAX_ARGS或其
-n
选项的限制。@kojiro:是的,没有检查
rm
是否成功
xargs
自动调用
rm
所需的次数,还是我误解了你的评论?这是一个微妙的问题,但这个问题与作为复制品提出的“计算文件数”问题的区别在于,这个问题问到如何只计算成功删除的文件数。啊,我明白了,我没有注意到这一点。我添加了一个bash解决方案,应该可以做到这一点。@Thor,我去掉了尾部,得到了一个“纯”shell解决方案。
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
find "$DIR_TO_CLEAN" -type f -mtime +$DAYS_TO_SAVE -print0 \
| awk -v RS='\0' -v ORS='\0' '{ print } END { print NR }'  \
| xargs -0 rm