Grep

從文件中包含特定模式的目錄中刪除文件

  • April 15, 2022

假設我有一個名為“/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 的文件。請注意,使用\;結束-exechere(而不是 +)很重要,因為每個文件都需要單獨測試(否則退出程式碼grep -q將針對目前正在執行的整批文件)。

find的謂詞預設情況下是與在一起的,因此粗略的英文翻譯是“grep AND delete any files where the previous -execreturn true”。

這將適用於包含任何有效字元的文件名,包括 shell 元字元、換行符和其他空格。

最後,要刪除匹配項,請使用-delete代替-print

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$而不是 just DELETEME- 這是因為我們只想匹配包含 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 運算。

-print可以替換為或-delete實際-exec rm {} +刪除文件。


PS:對於比這更複雜的事情,我傾向於編寫一個 perl 腳本,可能使用File::Find模組。

有些東西用過程語言風格編寫比使用非常長的命令行(謂詞鏈與布爾運算符綁定在一起)要容易得多find(很容易忘記邏輯鏈)。

引用自:https://unix.stackexchange.com/questions/699116