问题:除了最新的3之外,如何删除目录中的所有文件?
查找最新的3个文件很简单:
ls -t | head -3
但我需要找到除最新的3个文件以外的所有文件。我该怎么做,如何在同一行中删除这些文件而不为其做一个不必要的for循环?
我正在使用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 --
解释这是如何工作的:
<mtime> <filename><NUL>
。sort -g -z
基于第一列(时间)执行一般(浮点,而不是整数)数字排序,其中行由NUL分隔。read
循环中的第一个while
剥离了mtime(在sort
完成后不再需要)。read
循环中的第二个while
读取文件名(运行到NUL)。xargs -0
然后将该文件名附加到它收集的argv列表中以调用rm
。ls -t | tail -n +4 | xargs -I {} rm {}
如果你想要1个衬垫
这是ceving和anubhava的答案的组合。这两种解决方案都不适合我。因为我一直在寻找一个应该每天运行的脚本来备份存档中的文件,所以我想避免ls
的问题(有人本可以在我的备份文件夹中保存一些有趣的命名文件)。所以我修改了提到的解决方案以满足我的需求。 Ceving的解决方案删除了三个最新的文件 - 而不是我需要和被问到的文件。
我的解决方案删除了除三个最新文件之外的所有文件。
find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
head -n -3 |
cut -d $'\t' -f 2- |
xargs rm
一些解释:
find
列出当前文件夹中的所有文件(不是目录)。它们打印出时间戳。
sort
根据时间戳(最旧的)对行进行排序。
head
打印出顶线,最后3行。
cut
删除了时间戳。
xargs
为每个选定的文件运行rm
。
为了验证我的解决方案:
(
touch -d "6 days ago" test_6_days_old
touch -d "7 days ago" test_7_days_old
touch -d "8 days ago" test_8_days_old
touch -d "9 days ago" test_9_days_old
touch -d "10 days ago" test_10_days_old
)
这将在当前文件夹中创建5个具有不同时间戳的文件。首先运行此脚本,然后运行用于删除旧文件的代码。
在zsh中:
rm /files/to/delete/*(Om[1,-4])
如果要包含点文件,请用(Om[1,-4]D)
替换带括号的部分。
我认为这适用于文件名中的任意字符(只需使用换行符检查)。
说明:括号包含Glob限定符。 O
的意思是“按顺序,降序”,m
表示mtime(请参阅man zshexpn
获取其他排序键 - 大型联机帮助页;搜索“已排序”)。 [1,-4]
仅返回基于1的索引1的匹配(last + 1 - 4)(注意-4
删除除3之外的所有匹配)。
不要使用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 --
ls -t | tail -n +4 | xargs -I {} rm {}
Michael Ballent的答案效果最佳
ls -t | tail -n +4 | xargs rm --
如果我的文件少于3个,则抛出错误
这使用find
而不是ls
与Schwartzian transform。
find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
tail -3 |
cut -d $'\t' -f 2-
find
搜索文件并用时间戳装饰它们,并使用制表器分隔这两个值。 sort
通过制表器拆分输入并执行常规数字排序,正确排序浮点数。 tail
应该是显而易见的,而cut
是不明显的。
装饰的问题一般是找到一个合适的分隔符,它不是输入的一部分,即文件名。这个answer使用NULL字符。