文件批量删除

文件批量删除

我想删除一个目录及其子目录中的所有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

此替代方案比任何 -execdir' 操作都更有效,因为它完全避免了分叉新进程和使用/bin/rm' 的-exec' or开销。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 findBDS 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

相关内容