我有一个扩展名列表:
avi,mkv,wmv,mp4,mp5,flv,M4V,mpeg,mov,m1v,m2v,3gp,avchd
我想在Linux中删除指定扩展名以外的所有文件,以及没有扩展名的文件。
如何使用rm命令实现这个功能?
首先,您需要找到不包含这些扩展名的文件。您可以使用 find
命令非常容易地完成此操作。您可以基于以下命令构建 -
find /path/to/files ! -name "*.avi" -type f -exec rm -i {} \;
你也可以使用-regex
代替-name
来进行复杂的搜索模式匹配。使用!
来否定搜索,这样就能够列出不包含这些扩展名的文件。rm -i
删除文件之前最好先列出所有文件,这样做可以避免误删,但如果列表很长的话可能会比较烦琐,你可以自行决定是否使用该命令。rm
命令之前应该先用find
命令检查列表,确保没有误删的文件。aculich
在评论中所述,你也可以采用以下方法 -find /path/to/files ! -name "*.avi" -type f -delete
-type f
将确保只查找
和删除
普通文件,不会触及任何目录、符号链接等。
rm
命令来完成想要的任务,但请记住它是容易出错、不可移植、危险且有严重限制。find
命令。我几乎在所有情况下都建议使用find
而不是rm
。find
命令,因为它给你一种精确的表达能力和安全性,你在大多数其他方法中都无法找到这种能力,除非你本质上(糟糕地)重新发明了这个命令!
< h2 >查找示例
人们经常建议以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
文件。
-regextype posix-extended
的简写,但即使如此,我仍然建议使用它,因为您可以避免在更长、更复杂的正则表达式中添加大量的 \
反斜杠转义问题,并且它具有更高级(现代)的功能。GNU实现默认使用emacs风格的正则表达式,如果您不习惯它们,可能会感到困惑。
-delete
选项应该很容易理解,但有时人们建议使用更慢、更复杂的-exec rm {} \;
选项,但通常是因为他们不知道更安全、更快、更容易的-delete
选项(在极少数情况下,您可能会遇到一个古老版本的find
没有这个选项)。了解-exec
的存在很有用,但在删除文件时尽量使用-delete
。此外,不要将find
的输出通过管道符|
传递给另一个程序,除非您使用并理解了-print0
选项,否则当您遇到带有空格的文件时,您将会遇到麻烦。path/to/files
参数。如果您将其省略,它将隐式地使用.
作为路径,但明确指定路径更安全(特别是使用-delete
)。
find
变体!-E
选项来实现与使用-regextype posix-extended
的GNU变体相同的行为。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
之前出现,而对于GNU的-regextype posix-extended
选项则在路径之后出现。-E
选项(还没有!);由于我认为这将是一个有用的选项,以便与BSD变体保持一致,我将提交一个补丁到findutils
中添加此选项,如果被接受,我将相应更新这个答案。
rm
,但我将给出如何完成您特定问题的示例(带有一些警告)。for ext in avi mkv wmv mp4 mp5 flv M4V mpeg mov m1v m2v 3gp avchd; do rm -f path/to/files/*.$ext; done
shopt -s extglob
),那么您可以使用文件名扩展的模式匹配:rm -f path/to/files/*.+(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)
+(pattern-list)
扩展的 globbing 语法将匹配给定模式的一个或多个出现。
然而,我强烈建议不要使用 rm
,因为:
它容易出错且危险,因为很容易在 *
之间意外添加空格,这意味着您将删除 所有;您无法预览命令的结果;它是“点火并忘记”的,所以祝好运。
它是非便携的,因为即使它在您特定的 shell 中工作,同一条命令可能在其他 shell(包括其他 Bourne-shell 变种,如果您倾向于使用 Bash-ism)中无法工作。
它有严重的限制,因为如果您有嵌套在子目录中的文件,甚至只是单个目录中有大量文件,那么在使用文件 globbing 时,您很快就会遇到命令行长度的限制。
我希望 rm
命令会彻底消失,因为除了(即使是古老的实现)find
,我几乎找不到比它更好用的地方了。
使用Bash,您可以先启用extglob选项:
$ shopt -s extglob
然后执行以下操作:
(注:此命令将删除除.avi、.mkv、.wmv和.mp4以外的所有文件,并在删除前提示确认)$ rm -i !(*.avi | *.mkv | *.wmv | *.mp4)
-delete
而不是-exec rm
; 您的实现可能已经有了,所以请使用它! - aculich