删除bash脚本中除最新3之外的所有文件

问题:如何删除除最新3之外的所有文件?

find最新的3个文件很简单:

ls -t | head -3 

但我需要find除最新的3个文件以外的所有文件。 我该怎么做,如何在同一行删除这些文件,而不必为此循环?

我正在使用Debian Wheezy和bash脚本。

这将列出除最新三个以外的所有文件:

 ls -t | tail -n +4 

这将删除这些文件:

 ls -t | tail -n +4 | xargs rm -- 

这也将列出dotfiles:

 ls -At | tail -n +4 

并用dotfiles删除:

 ls -At | tail -n +4 | xargs rm -- 

但要小心:当文件名包含有趣的字符如换行符或空格时,解析ls可能会很危险。 如果您确定您的文件名不包含有趣的字符,那么解析ls是相当安全的,如果它是一次性脚本,则更是如此。

如果您正在开发一个重复使用的脚本,那么您绝对不应该解析ls的输出,并使用下面描述的方法: http : //mywiki.wooledge.org/ParsingLs

以下看起来有点复杂,但是非常谨慎是正确的,即使是不寻常的或故意的恶意文件名。 不幸的是,它需要GNU工具:

 count=0 while IFS= read -r -d ' ' && IFS= read -r -d '' filename; do (( ++count > 3 )) && printf '%s\0' "$filename" done < <(find . -maxdepth 1 -type f -printf '%T@ %P\0' | sort -g -z) \ | xargs -0 rm -f -- 

解释这是如何工作的:

  • Find为当前目录中的每个文件发出<mtime> <filename><NUL>
  • sort -g -z基于第一列(时间)用NUL分隔的行做一般的(浮点数,而不是整数)数值排序。
  • while循环中的第一次read剥离了mtime( sort完成后不再需要)。
  • while循环中的第二次read读取文件名(运行直到NUL)。
  • 循环递增,然后检查计数器; 如果计数器的状态表明我们已经超过了最初的跳过,那么我们打印由NUL分隔的文件名。
  • xargs -0然后把这个文件名附加到它正在收集的argv列表中以调用rm
 ls -t | tail -n +4 | xargs -I {} rm {} 

如果你想要一个班轮

这使用find而不是与Schwartzian变换 ls

 find . -type f -printf '%T@\t%p\n' | sort -t $'\t' -g | tail -3 | cut -d $'\t' -f 2- 

find搜索文件,并用时间戳来装饰它们,并使用制表符分隔这两个值。 sort分割tabulator的输入,并执行一个普通的数字排序,正确地排序浮点数。 tail应该是明显的, cut undecorates。

装饰的问题一般是找到一个合适的分隔符,而不是输入文件名的一部分。 这个答案使用NULL字符。

不要使用ls -t因为对于可能包含空格或特殊的glob字符的文件名是不安全的。

您可以使用所有基于gnu的实用程序来删除当前目录中的所有3个最新文件:

 find . -maxdepth 1 -type f -printf '%T@\t%p\0' | sort -z -nrk1 | tail -z -n +4 | cut -z -f2- | xargs -0 rm -f --