19

我有一个扩展列表:

avi,mkv,wmv,mp4,mp5,flv,M4V,mpeg,mov,m1v,m2v,3gp,avchd

我想删除所有没有以下扩展名的文件以及 linux 目录中没有扩展名的文件。

如何使用 rm linux 命令执行此操作?

4

3 回答 3

33

您首先必须找出不包含这些扩展名的文件。您可以使用该find命令轻松完成此操作。您可以基于以下命令进行构建 -

find /path/to/files ! -name "*.avi" -type f -exec rm -i {} \;

您也可以使用-regex而不是-name提供复杂的搜索模式。!是否定搜索。因此它将有效地列出那些不包含这些扩展名的文件。

这样做很好,rm -i因为它会在删除之前列出所有文件。如果您的清单很全面,可能会变得乏味,因此您可以决定自己是否包含它。

使用它删除大量文件可能很危险。一旦删除,您将永远无法找回它们。因此,在删除它们之前,请确保在没有先检查列表的情况下运行该find命令。rm

更新:

如评论中所述aculich,您还可以执行以下操作 -

find /path/to/files ! -name "*.avi" -type f -delete

-type f将确保它只会finddelete 常规文件,并且不会触及任何目录、符号链接等

于 2011-12-27T08:11:07.230 回答
13

您可以使用快速而肮脏的rm命令来完成您想要的操作,但请记住,它容易出错、不可移植、危险并且有严重的限制

正如其他人所建议的,您可以使用该find命令。我建议在几乎所有情况下都使用find而不是。rm

既然你提到你在 Linux 系统上,我将在我的示例中使用作为findutils 包一部分的GNU 实现,因为它是大多数 Linux 系统上的默认设置,并且我通常建议学习它,因为它有更丰富和更多比许多其他实现更先进的功能集。

尽管它可能令人生畏并且看似过于复杂,但值得花时间掌握该find命令,因为它为您提供了一种精确的表现力和安全性,如果不从本质上(较差地)重新发明此命令,您将无法使用大多数其他方法找到!

查找示例

人们经常建议以低效、容易出错和危险的方式find使用该命令,因此在下面我概述了一种安全有效的方法来准确地完成您在示例中所要求的内容。

在删除文件之前,我建议先预览文件列表(如果列表很长,则至少预览部分列表):

find path/to/files -type f -regextype posix-extended -iregex '.*\.(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)$'

上面的命令将显示您将要删除的文件列表。要实际删除文件,您可以简单地添加如下-delete操作:

find path/to/files -type f -regextype posix-extended -iregex '.*\.(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)$' -delete

如果您想查看剩下的内容,您可以通过添加!到预览命令(不带)来反转预览中的匹配项,-delete如下所示:

find path/to/files -type f -regextype posix-extended ! -iregex '.*\.(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)$'

此反向匹配的输出应与您在执行删除后列出文件时看到的输出相同,除非由于权限问题或不可写文件系统而发生错误:

find path/to/files -type f

解释

在这里,我将深入解释我选择的选项以及原因:

我添加-type f将匹配限制为仅文件;没有它,它将匹配非文件,例如您可能不想要的目录。另请注意,我将它放在开头而不是结尾,因为谓词的顺序对速度很重要;首先-type f,它将仅针对文件而不是针对所有内容执行正则表达式检查……实际上,除非您有很多目录或非文件,否则它可能并不重要。尽管如此,记住谓词的顺序还是值得的,因为它在某些情况下会产生重大影响。

我使用不区分大小写 -iregex选项而不是区分大小写选项,-regex因为我假设您想使用不区分大小写的匹配,因此它将同时包含.wmv .WMV文件。

为了简单起见,您可能希望使用扩展 POSIX 正则表达式。不幸的是,还没有 的简写-regextype posix-extended,但即使如此,我仍然建议使用它,因为您可以避免必须添加大量\反斜杠以在更长、更复杂的正则表达式中转义的问题,并且它具有更高级(现代)的功能. GNU 实现默认为emacs 样式的正则表达式,如果您不习惯它们可能会造成混淆。

-delete选项应该很有意义,但是有时人们建议使用更慢和更复杂的-exec rm {} \;选项,但通常这是因为他们没有意识到更安全、更快和更简单的-delete选项(在极少数情况下,您可能会遇到具有古老的旧系统该版本find没有此选项)。知道-exec存在是有用的,但-delete在可以删除文件的地方使用。此外,除非您使用并理解该选项,否则不要|将输出通过管道传输到另一个程序,否则当您遇到带有空格的文件时,您将陷入痛苦的世界。find-print0

我明确包含的path/to/files论点。如果您将其省略,它将隐式.用作路径,但是-delete显式声明路径更安全(尤其是使用 a )。

备用查找实现

即使您说您使用的是 Linux 系统,我也会提到您在使用包括 Mac OS X的BSD 实现时会遇到的差异!对于其他系统(如旧的 Solaris 机器),祝你好运!升级到更现代的变体之一!find

此示例中的主要区别在于正则表达式。BSD 变体默认使用基本的 POSIX 正则表达式。为了避免在基本 PRE 所需的正则表达式中进行繁重的额外转义,您可以通过-E使用 BSD 变体指定选项来利用扩展 PRE 的更现代特性,以实现与使用-regextype posix-extended.

find -E path/to/files -iregex '.*\.(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)$' -type f

请注意,在这种情况下,-E选项位于路径之前path/to/files-regextype posix-extendedGNU 的选项位于路径之后

GNU 还没有提供-E选项太糟糕了(还没有!);因为我认为与 BSD 变体具有同等地位将是一个有用的选项,我将提交一个补丁以findutils添加此选项,如果被接受,我将相应地更新此答案。

rm - 不推荐

尽管我强烈建议不要使用rm,但我将举例说明如何或多或少地完成您的问题具体提出的问题(有一些警告)。

假设您使用具有 Bourne 语法的 shell(通常是您在 Linux 系统上找到的默认为 Bash shell),您可以使用以下命令:

for ext in avi mkv wmv mp4 mp5 flv M4V mpeg mov m1v m2v 3gp avchd; do rm -f path/to/files/*.$ext; done

如果您使用 Bash 并打开了扩展 globbing,shopt -s extglob那么您可以使用带有文件名扩展的模式匹配

rm -f path/to/files/*.+(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)

扩展的+(pattern-list)通配符语法将匹配给定模式的一次或多次出现。

但是,我强烈建议不要使用rm,因为:

容易出错且很危险,因为很容易在*'s 之间放置一个空格,这意味着您将删除所有内容;您无法提前预览命令的结果;这是一劳永逸的,所以祝你好运。

它是不可移植的,因为即使它恰好在您的特定 shell 中工作,相同的命令行也可能无法在其他 shell 中工作(包括其他 Bourne-shell 变体,如果您倾向于使用 Bash-isms)。

它有严重的限制,因为如果您有嵌套在子目录中的文件,或者甚至在单个目录中有很多文件,那么在使用文件通配符时,您将很快达到命令行长度的限制。

我希望该rm命令rm本身会被遗忘,因为我能想到几个我宁愿使用rm而不是(甚至是古老的实现)的地方find

于 2011-12-28T21:28:06.507 回答
4

使用 Bash,您可以首先启用 extglob 选项:

$ shopt -s extglob

并执行以下操作:

$ rm -i !(*.avi | *.mkv | *.wmv | *.mp4)

于 2014-11-08T11:52:01.217 回答