文件批量刪除

文件批量刪除

我想刪除一個目錄及其子目錄中的所有txt、xls、pdf檔。我想保存其他一切。

find . -type f ! -iname '*.xml$,.png$,.jpeg$,.gif$,' -delete

這似乎已經完成了,但它刪除了我需要的一些其他文件。我怎樣才能在不刪除其他內容的情況下實現這一目標?

答案1

改為這樣做:

find . -type f -iname '*.xml' -o -iname '*.png'\
       -o -iname '*.jpeg' -o -iname '*.gif' -delete

您也可以使用正規表示式:

find . -type f -iregex '.*\.\(xml\|png\|jpeg\|gif\)$' -delete

答案2

使用 find 基本上有 4 種方法來解決這個問題。

方法#1 - 使用-delete

$ find . -type f -iname '*.xml' -o -iname '*.png'\
       -o -iname '*.jpeg' -o -iname '*.gif' -delete

正如其他人在本問答中提到的,這種方法是最快且資源消耗最少的方法。引用自尋找線上文檔:

10.1.6 使用`-delete'操作


解決這個問題最有效、最安全的方法是使用「-delete」操作:

 find /var/tmp/stuff -mtime +90 -delete

這個替代方案比任何-exec' or-execdir' 操作都更有效,因為它完全避免了分叉新進程和使用 /bin/rm' 的開銷exec' to run。它通常也比xargs' for the same reason. The file deletion is performed from the directory containing the entry to be deleted, so the“-delete”操作更有效,並且具有與“-execdir”操作相同的安全性優勢。

「-delete」操作是由 BSD 系列作業系統引入的。

筆記:使用這種方法要記住一件事,使用-delete也意味著 switch -depth。這是什麼意思?這裡有一個例子,說明-delete如果您不小心,可能會被燒傷。

例如,假設我有一個 subversion 工作目錄,我想在其中清理一些文件,但保持其 .svn 子目錄不變。我可能會使用以下命令來完成此操作:

$ find . -not "(" -name .svn -type d -prune ")" -type f -print
./a.txt

但因為-delete包含一個-depth開關,所以實際要處理的文件是:

$ find . -not "(" -name .svn -type d -prune ")" -type f -print -depth
./.svn/all-wcprops
./.svn/entries
./.svn/format
./.svn/text-base/a.txt.svn-base
./a.txt

因此,使用時-delete必須小心。

方法#2 --exec command {} +

$ find . -type f -iname '*.xml' -o -iname '*.png'\
       -o -iname '*.jpeg' -o -iname '*.gif' -exec rm {} \+

與該方法相比-delete,就跨 Unix 的性能和可移植性而言,這很可能是下一個最佳選擇。該-exec ... {} +符號的工作原理如下:

從尋找手冊頁

-exec 操作的此變體對所選檔案執行指定的命令,但命令列是透過在末尾附加每個所選檔案名稱來建構的;該命令的調用總數將遠小於匹配的檔案數。命令列的建構方式與 xargs 建構其命令列的方式大致相同。命令中只允許有一個「{}」實例。該指令在起始目錄中執行。

因此,實際上,此方法的工作原理與 類似xargs,但無需跳過將 find 的輸出通過管道傳遞到 的麻煩xargs

方法#3 -xargs

$ find . -type f -iname '*.xml' -o -iname '*.png'\
       -o -iname '*.jpeg' -o -iname '*.gif' -print0 | xargs -0 rm -f

find ... -print0建立符合指定條件的文件清單。然後該列表通過管道傳遞到xargs。此-print0開關在 find 的每個結果之間放置一個 ASCII NUL 字元作為分隔符號。開啟-0開關xargs會假設傳入的檔案由 ASCII NUL 字元分隔。

與方法 #1 和 #2 相比,該方法具有與方法 #2 相似的效能,但-print0並非所有 Unix 系統都普遍支援該切換。

方法 #4 --exec command {} \;

$ find . -type f -iname '*.xml' -o -iname '*.png'\
       -o -iname '*.jpeg' -o -iname '*.gif' | exec rm -f {} \;

與前 3 種方法相比,這是性能最低的。它從字面上rm為該命令找到的每個單獨檔案調用該命令find

有關安全性的其他注意事項

使用上述任何方法時可能不太明顯的一件事是,某些方法比其他方法更安全。您可能會對自己說,...安全? .. 什麼?這是一個例子。

假設您是 root 並執行以下命令:

$ find /var/tmp/somedir -type f -exec rm {} \;

/etc在您不知道的情況下,有人惡意創建了指向/var/tmp/somedir.當上述命令運行時,該/etc目錄也將被刪除。除了-delete選項(方法 #1)之外,任何刪除檔案的方法都存在此問題。

太長;博士;

借助 find 刪除檔案最快、最安全的方法是使用-delete.使用xargs -0效能可以相似,但安全性較差。該-delete動作並不完全可移植。最有效的可移植替代方案是-exec ... +,但這是不安全的,並且 4.2.12 之前的 GNU findutils 版本不支援。

參考

答案3

有一點點不準確slm 答案

注意與免責聲明: 這必須是個評論slm 答案但現在我還不能發表評論。

範例“有人惡意創建了連結”有關安全性的其他注意事項關於 Unix 硬連結和 Unix 軟連結都不完全準確。

要了解兩者之間的區別,請參閱Unix 中的硬鏈接和符號鏈接或者用谷歌搜尋一下。

對於軟連結(無論如何都是最常用的類型),GNU find並且BDS find 才不是遵循符號鏈接,除非使用特定-L標誌來強制遵循符號鏈接。 [看man find]

所以這個例子可能不是問題,除非你力量 find使用該標誌追蹤軟連結-L。無論如何,這是一個危險的選擇。

對於硬鏈接,find將點擊鏈接到另一個文件但請注意,硬連結到另一個目錄“可能會失敗”,如man lnGNU所示ln

   -d, -F, --directory
          allow the superuser to attempt to hard link directories (note: will probably
          fail due to system restrictions, even for the superuser)

因此,一開始可能不可能創建到目錄的​​硬鏈接,並且find沒有任何可遵循的內容。

請注意,某些 BDS實作根本ln沒有選項。-d

相關內容