从文件中包含特定模式的目录中删除文件

从文件中包含特定模式的目录中删除文件

假设我有一个名为“/home/ben/files”的目录,其中包含 100 个随机命名的文本文件。在 100 个文本文件中,有些文本文件中仅包含单词“DELETEME”。

例如file1.txt,file2.txt,file3.txt,file4.txt,file5.txt.....等

应该如何删除此类包含该模式的文件?

答案1

至少使用 GNU grep,你可以尝试:

grep -lZr "DELETEME" /home/ben/files | xargs -0 rm

警告:这将通过/home/ben/files;的子文件夹进行递归如果您不想这样做,则需要采取更多预防措施。

(感谢评论中的 cas 建议使用空分隔符。)

答案2

使用 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

这将打印返回 true 的所有文件grep -q DELETEME。请注意,重要的是使用\;来结束-exec这里(和不是 +),因为每个文件都需要单独测试(否则退出代码grep -q将针对当前正在运行的整批文件)。

find的谓词默认是通过 AND 操作连接在一起的,因此,其作用粗略的英语翻译为“grep AND 删除任何前一个-exec返回 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

打印包含 DELETEME 和其他内容的文件列表:

$ find ./files/ -type f -exec grep -q '^DELETEME$' {} \; -exec grep -vq '^DELETEME$' {} \; -print
./files/001

在本例中,我们使用正则表达式^DELETEME$而不仅仅是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 脚本,可能使用文件::查找模块。

有些事只是很多用过程语言风格编写比使用极长的find命令行(带有与布尔运算符捆绑在一起的谓词链)更容易(很容易失去逻辑链)。

相关内容