Linux Shell 脚本来计算文件,然后删除最旧的文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2960022/
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-08-03 20:05:21  来源:igfitidea点击:

Shell script to count files, then remove oldest files

linuxbashshell

提问by Nic Hubbard

I am new to shell scripting, so I need some help here. I have a directory that fills up with backups. If I have more than 10 backup files, I would like to remove the oldest files, so that the 10 newest backup files are the only ones that are left.

我是 shell 脚本的新手,所以我需要一些帮助。我有一个充满备份的目录。如果我有 10 个以上的备份文件,我想删除最旧的文件,以便只剩下 10 个最新的备份文件。

So far, I know how to count the files, which seems easy enough, but how do I then remove the oldest files, if the count is over 10?

到目前为止,我知道如何计算文件数,这似乎很容易,但是如果计数超过 10,我该如何删除最旧的文件?

if [ls /backups | wc -l > 10]
    then
        echo "More than 10"
fi

采纳答案by Dale Hagglund

Try this:

尝试这个:

ls -t | sed -e '1,10d' | xargs -d '\n' rm

This should handle all characters (except newlines) in a file name.

这应该处理文件名中的所有字符(换行符除外)。

What's going on here?

这里发生了什么?

  • ls -tlists all files in the current directory in decreasing order of modification time. Ie, the most recently modified files are first, one file name per line.
  • sed -e '1,10d'deletes the first 10 lines, ie, the 10 newest files. I use this instead of tailbecause I can never remember whether I need tail -n +10or tail -n +11.
  • xargs -d '\n' rmcollects each input line (without the terminating newline) and passes each line as an argument to rm.
  • ls -t按修改时间降序列出当前目录中的所有文件。即,最近修改的文件是第一个,每行一个文件名。
  • sed -e '1,10d'删除前 10 行,即 10 个最新的文件。我使用它而不是tail因为我永远不记得我是否需要tail -n +10tail -n +11.
  • xargs -d '\n' rm收集每个输入行(没有终止换行符)并将每一行作为参数传递给rm.

As with anything of this sort, please experiment in a safe place.

与此类任何事情一样,请在安全的地方进行试验。

回答by barrycarter

Experiment with this, because I'm not 100% sure it'll work:

对此进行试验,因为我不是 100% 确定它会起作用:

cd /backups; ls -at | tail -n +10 | xargs -I{} "rm '{}'"

回答by bta

stat -c "%Y %n" * | sort -rn | head -n +10 | \
        cut -d ' ' -f 1 --complement | xargs -d '\n' rm

Breakdown: Get last-modified times for each file (in the format "timefilename"), sort them from oldest to newest, keep all but the last ten entries, and then keep all but the first field (keep only the filename portion).

细分:获取每个文件的最后修改时间(格式为“ timefilename”),将它们从最旧到最新排序,保留除最后十个条目之外的所有条目,然后保留除第一个字段之外的所有条目(仅保留文件名部分)。

Edit: Using cutinstead of awksince the latter is not always available

编辑:使用cut而不是awk因为后者并不总是可用

Edit 2: Now handles filenames with spaces

编辑 2:现在处理带空格的文件名

回答by Paused until further notice.

The proper way to do this type of thing is with logrotate.

做这种事情的正确方法是使用logrotate.

回答by bashfu

Using inode numbers via stat & find command (to avoid pesky-chars-in-file-name issues):

通过 stat & find 命令使用 inode 编号(以避免麻烦的文件名字符问题):

stat -f "%m %i" * | sort -rn -k 1,1 | tail -n +11 | cut -d " " -f 2 | \
   xargs -n 1 -I '{}' find "$(pwd)" -type f -inum '{}' -print

#stat -f "%m %i" * | sort -rn -k 1,1 | tail -n +11 | cut -d " " -f 2 | \
#   xargs -n 1 -I '{}' find "$(pwd)" -type f -inum '{}' -delete 

回答by Daniel Haley

I like the answers from @Dennis Williamson and @Dale Hagglund. (+1 to each)

我喜欢@Dennis Williamson 和@Dale Haglund 的回答。(每个+1)

Here's another way to do it using find(with the -newertest) that is similar to what you started with.

这是使用find(通过-newer测试)的另一种方法,类似于您开始使用的方法。

This was done in bash on cygwin...

这是在 cygwin 上的 bash 中完成的...

if [[ $(ls /backups | wc -l) > 10 ]]
then
  find /backups ! -newer $(ls -t | sed '11!d') -exec rm {} \;
fi

回答by mikecolley

Make sure your pwd is the correct directory to delete the files then(assuming only regular characters in the filename):

确保您的密码是删除文件的正确目录(假设文件名中只有常规字符):

ls -A1t | tail -n +11 | xargs rm

keeps the newest 10 files. I use this with camera program 'motion' to keep the most recent frame grab files. Thanks to all proceeding answers because you showed me how to do it.

保留最新的 10 个文件。我将它与相机程序“运动”一起使用以保留最新的帧抓取文件。感谢所有进行中的答案,因为您向我展示了如何去做。

回答by John Andrea

Straightforward file counter:

简单的文件计数器:

max=12
n=0
ls -1t *.dat |
while read file; do
    n=$((n+1))
    if [[ $n -gt $max ]]; then
        rm -f "$file"
    fi
done

回答by mahyard

findis the common tool for this kind of task :

find是这种任务的常用工具:

find ./my_dir -mtime +10 -type f -delete

EXPLANATIONS

说明

  • ./my_diryour directory (replace with your own)
  • -mtime +10older than 10 days
  • -type fonly files
  • -deleteno surprise. Remove it to test your findfilter before executing the whole command
  • ./my_dir您的目录(替换为您自己的)
  • -mtime +10超过 10 天
  • -type f只有文件
  • -delete没有惊喜。在执行整个命令之前删除它以测试您的find过滤器

And take care that ./my_direxists to avoid bad surprises !

并注意./my_dir存在以避免糟糕的惊喜!

回答by miron

On a very limited chroot environment, we had only a couple of programs available to achieve what was initially asked. We solved it that way:

在非常有限的 chroot 环境中,我们只有几个程序可以实现最初的要求。我们是这样解决的:

MIN_FILES=5
FILE_COUNT=$(ls -l | grep -c ^d )


if [ $MIN_FILES -lt $FILE_COUNT  ]; then
  while [ $MIN_FILES -lt $FILE_COUNT ]; do
    FILE_COUNT=$[$FILE_COUNT-1]
    FILE_TO_DEL=$(ls -t | tail -n1)
    # be careful with this one
    rm -rf "$FILE_TO_DEL"
  done
fi

Explanation:

解释:

  • FILE_COUNT=$(ls -l | grep -c ^d )counts all files in the current folder. Instead of grep we could use also wc -lbut wc was not installed on that host.
  • FILE_COUNT=$[$FILE_COUNT-1]update the current $FILE_COUNT
  • FILE_TO_DEL=$(ls -t | tail -n1)Save the oldest file name in the $FILE_TO_DELvariable. tail -n1returns the last element in the list.
  • FILE_COUNT=$(ls -l | grep -c ^d )计算当前文件夹中的所有文件。我们也可以使用 grep 代替 grep,wc -l但该主机上未安装 wc。
  • FILE_COUNT=$[$FILE_COUNT-1]更新当前 $FILE_COUNT
  • FILE_TO_DEL=$(ls -t | tail -n1)将最旧的文件名保存在$FILE_TO_DEL变量中。tail -n1返回列表中的最后一个元素。