[英]Clean a maven repository - Delete all files except the x newest per folder
[英]Delete all files except the newest 3 in bash script
问题:如何删除目录中除最新的 3 个之外的所有文件?
查找最新的 3 个文件很简单:
ls -t | head -3
但我需要找到除最新的 3 个文件之外的所有文件。 我该怎么做,以及如何删除同一行中的这些文件而不需要为此进行循环?
为此,我正在使用 Debian Wheezy 和 bash 脚本。
这将列出除最新的三个文件之外的所有文件:
ls -t | tail -n +4
这将删除这些文件:
ls -t | tail -n +4 | xargs rm --
这还将列出点文件:
ls -At | tail -n +4
并用点文件删除:
ls -At | tail -n +4 | xargs rm --
但请注意:当文件名包含有趣的字符(如换行符或空格)时,解析ls
可能会很危险。 如果您确定您的文件名不包含有趣的字符,那么解析ls
是非常安全的,如果它是一次性脚本,则更是如此。
如果您正在开发重复使用的脚本,那么您肯定不应该解析ls
的输出并使用此处描述的方法: http : //mywiki.wooledge.org/ParsingLs
这是 ceving 和 anubhava 的答案的结合。 这两种解决方案都不适合我。 因为我正在寻找一个应该每天运行的脚本来备份存档中的文件,所以我想避免ls
出现问题(有人可以在我的备份文件夹中保存一些有趣的命名文件)。 所以我修改了提到的解决方案以满足我的需求。
我的解决方案删除所有文件,但三个最新文件除外。
find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
head -n -3 |
cut -d $'\t' -f 2- |
xargs rm
一些解释:
find
列出当前文件夹中的所有文件(不是目录)。 它们与时间戳一起打印出来。
sort
根据时间戳(最旧的在顶部)对行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 个具有不同时间戳的文件。 先运行这个脚本,然后运行删除旧文件的代码。
以下看起来有点复杂,但非常谨慎,即使是不寻常的或故意恶意的文件名也是如此。 不幸的是,它需要 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 分隔的行进行一般(浮点数,而不是整数)数字排序。while
循环中的第一次read
去除 mtime( sort
完成后不再需要)。while
循环中的第二次read
读取文件名(运行直到 NUL)。xargs -0
然后将该文件名附加到它正在收集以调用rm
的 argv 列表中。ls -t | tail -n +4 | xargs -I {} rm {}
如果你想要一个 1 班轮
在 zsh 中:
rm /files/to/delete/*(Om[1,-4])
如果要包含dotfiles ,请将括号中的部分替换为(Om[1,-4]D)
。
我认为这适用于文件名中的任意字符(只是用换行符检查)。
说明:括号包含 Glob 限定符。 O
表示“排序,降序”, m
表示 mtime(有关其他排序键,请参阅man zshexpn
- 大型联机帮助页;搜索“被排序”)。 [1,-4]
仅返回基于一的索引 1 到 (last + 1 - 4) 的匹配项(注意-4
表示删除除 3 之外的所有项)。
ls -t | tail -n +4 | xargs -I {} rm {}
Michael Ballent 的回答最有效
ls -t | tail -n +4 | xargs rm --
如果我的文件少于 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 --
#!/bin/bash
if (( $# != 2 )); then
echo "Usage: $0 </path/to/top-level/dir> <num files to keep per dir>"
exit
fi
while IFS= read -r -d $'\0' dir; do
# Find the nth oldest file
nthOldest=$(find "$dir" -maxdepth 1 -type f -printf '%T@\0%p\n' | sort -t '\0' -rg \
| awk -F '\0' -v num="$2" 'NR==num+1{print $2}')
if [[ -f "$nthOldest" ]]; then
find "$dir" -maxdepth 1 -type f ! -newer "$nthOldest" -exec rm {} +
fi
done < <(find "$1" -type d -print0)
$ tree test/
test/
├── sub1
│ ├── sub1_0_days_old.txt
│ ├── sub1_1_days_old.txt
│ ├── sub1_2_days_old.txt
│ ├── sub1_3_days_old.txt
│ └── sub1\ 4\ days\ old\ with\ spaces.txt
├── sub2\ with\ spaces
│ ├── sub2_0_days_old.txt
│ ├── sub2_1_days_old.txt
│ ├── sub2_2_days_old.txt
│ └── sub2\ 3\ days\ old\ with\ spaces.txt
└── tld_0_days_old.txt
2 directories, 10 files
$ ./keepNewest.sh test/ 2
$ tree test/
test/
├── sub1
│ ├── sub1_0_days_old.txt
│ └── sub1_1_days_old.txt
├── sub2\ with\ spaces
│ ├── sub2_0_days_old.txt
│ └── sub2_1_days_old.txt
└── tld_0_days_old.txt
2 directories, 5 files
这使用find
而不是ls
与Schwartzian 变换。
find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
tail -3 |
cut -d $'\t' -f 2-
find
搜索文件并用时间戳装饰它们,并使用制表符将两个值分开。 sort
通过制表符拆分输入并执行通用数字排序,从而正确对浮点数进行排序。 tail
应该很明显, cut
装饰的东西。
装饰的问题通常是找到一个合适的分隔符,它不是输入文件名的一部分。 此答案使用 NULL 字符。
作为flohall 答案的扩展。 如果要删除除最新的三个文件夹之外的所有文件夹,请使用以下命令:
find . -maxdepth 1 -mindepth 1 -type d -printf '%T@\t%p\n' |
sort -t $'\t' -g |
head -n -3 |
cut -d $'\t' -f 2- |
xargs rm -rf
-mindepth 1
将忽略父文件夹和-maxdepth 1
子文件夹。
以下对我有用:(干杯🍾)
rm -rf $(ll -t | tail -n +5 | awk '{ print $9}')
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.