
我有一個腳本,當超過設定限制時,我想清除舊文件。
我有這個指令:
/bin/rm -f `/bin/ls -t $bkup_p/mysql.daily/* 2> /dev/null | /bin/awk 'NR>'5`
這是可行的,因為 $bkup_p 中可能有空格,我嘗試將其更改為
/bin/rm -f `/bin/ls -t "$bkup_p/mysql.daily/*" 2> /dev/null | /bin/awk 'NR>'5`
但這是行不通的。它不顯示有問題的文件,它只是空的
答案1
在根據修改時間過濾檔案並對其執行命令時,Bash 並不是很方便。
我建議嘗試 z-shell,所以先運行zsh
,然後
rm -i -- "$bkup_p"/mysql.daily/*(DN.Om[1,5])
這將刪除給定目錄中最舊的五個純文件,我懷疑可能是您想要實現的目標。顯然,如果需要的話,最終會更改rm -i
為rm -f
。
若要刪除五個最新文件,請執行以下操作
rm -i -- "$bkup_p"/mysql.daily/*(DN.om[1,5])
現在,它是如何工作的。裡面的所有內容()
都是所謂的 glob 限定符,它基本上是根據您的需求過濾檔案:
D
包括點文件(以 開頭的文件.
)N
如果沒有符合則不報告錯誤.
僅選擇純文件om
依修改時間排序(Om
逆序排序)[1,5]
從清單中僅選擇五個文件
我相信所有這些都應該適用於檔案名稱中的特殊字元(空格、換行符等)
答案2
正如其他人所說,您不應該用於ls
此目的。但是如果你的環境沒有任何更明智的東西並且你了解注意事項, 你可能如果你的檔名是夠好:沒有空格或不可列印的字符,尤其是 shell 不會將其解釋為通配字元(至少?*[]
)。
使用 Perl 之類的東西對檔案進行排序,或者將日期放在檔案名稱中以便您可以依賴全域順序會更好。
話雖如此:在您的第二個片段中,星號被引用,因此不會發生通配符。您會看到有關不存在的錯誤some dir/mysql.daily/*
,但由於您將錯誤輸出重定向走了,所以您沒有看到。
帶有空格的檔案名稱會為您帶來一個問題,即命令替換的輸出沿著空格分割,因此類似的內容some dir/foo
將分為rm
兩部分:some
和dir/foo
。希望它們都不存在,因為它們會被刪除。
如果只有您的目錄名稱包含空格,您可以先cd
進入它。或者,設定IFS
為僅包含換行符(而不是預設的空格、製表符、換行符)。您提到了 NAS,那麼您很可能擁有 busybox。這應該適用於 busybox 和 bash,並列印文件名,每行一個:
IFS=$'\n'
printf "%s\n" $( ls -t "$bkup_p/mysql.daily/"* | tail -n +6 )
如果您確定其工作正常,請替換printf "%s\n"
為rm
以刪除檔案。
答案3
我建議不要解析 的輸出,ls
因為它不能正確格式化輸出以通過管道傳輸到新命令,並且它存在可移植性問題。
我會嘗試這樣的事情
find $bkup_p/mysql.daily/ -type f -a -mtime +7 -a -name "*.sql" -a -exec rm -f {} +
筆記:
"*.sql"
根據需要更改此設置-mtime +7
意味著*如果此文件在 7 天前被修改了更多 (+),顯然也可以根據需要更改此文件
如果您想確保始終擁有 10 個最新文件 - 無論如何,(並且您有 GNU find
)您可以嘗試
find $bkup_p/mysql.daily/ -maxdepth 1 -type f -a -printf "%T+\t%p\n" | sort -r | sed -n '10,$p' | awk '{print $2}' | xargs rm -f
有關使用運算find
符格式化輸出的更多信息-printf
,請參閱
man find | less '+/^\s*-printf'
答案4
不起作用的問題*
是因為當您引用它時,它不會擴展。
將以下結果echo *
與以下結果進行比較:echo "*"
。
可靠的解決方案是使用一個數組,每個數組位置上都有一個檔案。
如果你夠幸運並且你的發現支持這一點-printf
:
dir="$bkup_p/mysql.daily/"
find "$dir" -printf '%T@:%i\n'
所有檔案名稱都將被避免。每個文件都是一行。一行僅包含數字、可選的點和冒號。
這可以很容易地排序:
find "$dir" -printf '%T@:%i\n' | sort -rn
最簡單的陣列是位置參數。
這會將目錄中的所有檔案設定為位置參數清單:
set -f; set -- $(find "$dir" -printf '%T@:%i\n' | sort -n )
set -f 將避免擴充任何也是通配符的檔案名稱*
。要避免(刪除)前 6 個檔案名,只需shift
:
shift 5
然後對其餘文件執行您需要的操作:
for f
do rm -f "$(find "$dir" -inum "${f#*:}")"
done
整個劇本。
整個腳本(對於任何檔案名稱都穩健)變為:
dir="$bkup_p/mysql.daily/"
set -f
set -- $(find "$dir" -type f -printf '%T@:%i\n'|sort -rn)
shift 5
for f
do rm -f "$(find "$dir" -inum "${f#*:}")"
done