整個劇本。

整個劇本。

我有一個腳本,當超過設定限制時,我想清除舊文件。

我有這個指令:

/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 -irm -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兩部分:somedir/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

相關內容