
我想刪除一個目錄及其子目錄中的所有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 ln
GNU所示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