從文件中包含特定模式的目錄中刪除文件
假設我有一個名為“/home/ben/files”的目錄,其中包含 100 個隨機命名的文本文件。在 100 個文本文件中,有些文本文件中只包含“刪除”一詞。
例如file1.txt、file2.txt、file3.txt、file4.txt、file5.txt…..等
應該如何刪除包含該模式的此類文件?
至少使用 GNU grep,您可以嘗試:
grep -lZr "DELETEME" /home/ben/files | xargs -0 rm
警告:這將通過 ; 的子文件夾遞歸
/home/ben/files
。如果您不希望這樣,則需要採取更多預防措施。(感謝 cas 在評論中建議使用空分隔符。)
使用 GNU
find
:首先進行一些設置,創建一個目錄,在其中創建 100 個空文件,並將“DELETEME”附加到其中一些文件:
mkdir files touch files/{001..100} for i in 001 010 020 030 040 050 065 077 088 099 ; do echo "DELETEME" >> files/$i ; done
接下來,列出包含 DELETEME 的文件:
find ./files/ -type f -exec grep -q DELETEME {} \; -print ./files/050 ./files/001 ./files/065 ./files/020 ./files/040 ./files/030 ./files/088 ./files/077 ./files/099 ./files/010
這將列印所有
grep -q DELETEME
返回 true 的文件。請注意,使用\;
結束-exec
here(而不是+
)很重要,因為每個文件都需要單獨測試(否則退出程式碼grep -q
將針對目前正在執行的整批文件)。
find
的謂詞預設情況下是與在一起的,因此粗略的英文翻譯是“grep AND delete any files where the previous-exec
return true”。這將適用於包含任何有效字元的文件名,包括 shell 元字元、換行符和其他空格。
最後,要刪除匹配項,請使用
-delete
代替find ./files/ -type f -exec grep -q DELETEME {} \; -delete
如果您使用的
find
是沒有的版本,則-delete
可以-exec
再次使用:find ./files/ -type f -exec grep -q DELETEME {} \; -exec rm {} +
我們可以在這裡使用
+
第二個-exec
,因為文件名不需要單獨刪除,批量刪除它們會更好更快。當然,您可以使用任何 find 的其他謂詞 - 例如
-maxdepth 1
防止遞歸。順便說一句,如果您想刪除僅包含“DELETEME”而沒有其他內容的文件,您需要更像這樣:
首先確保我們至少有一個這樣的文件。
$ echo "DON'T DELETEME" > files/001
列印包含 DELETME 以及其他任何內容的文件列表:
$ find ./files/ -type f -exec grep -q '^DELETEME$' {} \; -exec grep -vq '^DELETEME$' {} \; -print ./files/001
在這種情況下,我們使用 regexp
^DELETEME$
而不是 justDELETEME
- 這是因為我們只想匹配包含 DELETEME 的行,而該行上沒有任何其他內容。如果您想在一行中允許可選的前導和/或尾隨空格,請使用^[[:space:]]*DELETEME[[:space:]]*$
然後我們將其與另一個
-exec grep
匹配包含除^DELETEME$
.我們現在可以繼續列出包含 DELETEME 的文件,除了那些包含其他內容的文件,使用
!
(boolean NOT) 來否定第二個-exec
:$ find ./files/ -type f -exec grep -q '^DELETEME$' {} \; ! -exec grep -vq '^DELETEME$' {} \; -print ./files/050 ./files/065 ./files/020 ./files/040 ./files/030 ./files/088 ./files/077 ./files/099 ./files/010
請注意,
./files/001
此列表中缺少文件,這正是我們想要的。還要注意
!
緊接在第二個-exec
謂詞之前。這很重要,也很容易錯過,所以我明確指出。在此範例中,第一個
-exec grep
獲取包含 的文件列表^DELETEME$
,然後它與包含除 ^DELETEME$ 以外的任何文件的文件進行 NOT AND 運算。
-delete
實際-exec rm {} +
刪除文件。PS:對於比這更複雜的事情,我傾向於編寫一個 perl 腳本,可能使用File::Find模組。
有些東西用過程語言風格編寫比使用非常長的命令行(謂詞鏈與布爾運算符綁定在一起)要容易得多
find
(很容易忘記邏輯鏈)。