[英]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.