bash 使用 Unix find 计算和删除旧文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11636133/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 02:52:23  来源:igfitidea点击:

Count and remove old files using Unix find

bashunixksh

提问by Prashant Kumar

I want to delete files in $DIR_TO_CLEANolder than $DAYS_TO_SAVEdays. Easy:

我想删除$DIR_TO_CLEAN超过$DAYS_TO_SAVE几天的文件。简单:

find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec rm {} \;

I suppose we could add a -type for a -fflag for rm, but I really would like to count the number of files getting deleted.

我想我们可以为,添加一个-type f或一个-f标志rm,但我真的很想计算被删除的文件数量。

We could do this naively:

我们可以天真地这样做:

DELETE_COUNT=`find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE | wc -l`
find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec rm {} \;

But this solution leaves a lot to be desired. Besides the command duplication, this snippet overestimates the count if rmfailed to delete a file.

但是这个解决方案还有很多不足之处。除了命令重复之外,如果rm未能删除文件,此代码段会高估计数。

I'm decently comfortable with redirection, pipes (including named ones), subshells, xargs, tee, etc, but I am eager to learn new tricks. I would like a solution that works on both bash and ksh.

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

How would you count the number of files deleted by find?

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

采纳答案by kojiro

You could just use bash within find:

你可以在 find 中使用 bash:

find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec bash -c 'printf "Total: %d\n" $#; rm "$@"' _ {} +

Of course this can call bash -c …more than once if the number of files found is larger than MAX_ARGS, and it also can overestimate the count if rm fails. But solving those problems gets messy:

当然bash -c …,如果找到的文件数大于 MAX_ARGS,这可以调用多次,如果 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' _ {} +

This solution to avoid MAX_ARGS limits avoids find altogether. If you need it to be recursive, you'll have to use recursive globbing, which is only available in newer shells. (globstaris a bash 4 feature.)

这种避免 MAX_ARGS 限制的解决方案完全避免了 find 。如果您需要它是递归的,则必须使用递归通配符,它​​仅在较新的 shell 中可用。(globstar是 bash 4 功能。)

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: %d\n' "$count"

Here's an approach using find with printf (strictly compliant find doesn't have printf, but you can use printf as a standalone utility in that case).

这是将 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

回答by Thor

I would avoid -execand go for a piped solution:

我会避免-exec并寻求管道解决方案:

find "$DIR_TO_CLEAN" -type f -mtime +$DAYS_TO_SAVE -print0 \
| awk -v RS='
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
)
' -v ORS='##代码##' '{ print } END { print NR }' \ | xargs -0 rm

Using awkto count matches and pass them on to rm.

使用awk计数比赛和把它们交给rm

Update:

更新:

kojiromade me aware that the above solution does not count the success/fail rate of rm. As awkhas issues with badly named files I think the following bashsolution might be better:

kojiro让我意识到上述解决方案没有计算rm. 由于awk名称错误的文件存在问题,我认为以下bash解决方案可能更好:

##代码##