在 Linux 中删除所有没有以下扩展名的文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8642211/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:49:56  来源:igfitidea点击:

Remove all files that does not have the following extensions in Linux

linuxsshfindrm

提问by Tike

I have a list of extensions:

我有一个扩展列表:

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

I want to remove all files without the following extensions aswell as files without extension in a directory in linux.

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

How can I do this using the rm linux command?

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

回答by jaypal singh

You will first have to find out files that do not contain those extension. You can do this very easily with the findcommand. You can build on the following command -

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

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

You can also use -regexinstead of -nameto feed in complex search pattern. !is to negate the search. So it will effectively list out those files that do not contain those extensions.

您还可以使用-regex代替-name来输入复杂的搜索模式。!是否定搜索。所以它会有效地列出那些不包含这些扩展名的文件。

It is good to do rm -ias it will list out all the files before deleting. It may become tedious if your list is comprehensive so you can decide yourself to include it or not.

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

Deleting tons of files using this can be dangerous. Once deleted you can never get them back. So make sure you run the findcommand without the rmfirst to inspect the list throughly before deleting them.

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

Update:

更新:

As stated in the comments by aculich, you can also do the following -

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

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

-type fwill ensure that it will only findand deleteregular filesand will not touch any directories, sym links etc.

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

回答by aculich

You can use a quick and dirty rmcommand to accomplish what you want, but keep in mind it is error-prone, non-portable, dangerous, and has severe limitations.

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

As others have suggested, you can use the findcommand. I would recommend using findrather than rmin almost all cases.

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

Since you mention that you are on a Linux system I will use the GNU implementationthat is part of the findutils packagein my examples because it is the default on most Linux systems and is what I generally recommend learning since it has a much richer and more advanced set of features than many other implementations.

既然您提到您使用的是 Linux 系统,我将在我的示例中使用findutils 包中的GNU 实现,因为它是大多数 Linux 系统上的默认设置,也是我通常建议学习的内容,因为它具有更丰富、更多比许多其他实现更先进的功能集。

Though it can be daunting and seemingly over-complicatedit is worth spending time to master the findcommand because it gives you a kind of precise expressiveness and safetythat you won't find with most other methods without essentially (poorly) re-inventing this command!

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

Find Example

查找示例

People often suggest using the findcommand in inefficient, error-prone and dangerous ways, so below I outline a safe and effective wayto accomplish exactly what you asked for in your example.

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

Before deleting files I recommend previewing the file list first (or at least part of the list if it is very long):

在删除文件之前,我建议先预览文件列表(或者至少是列表的一部分,如果它很长):

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

The above command will show you the list of files that you will be deleting. To actually delete the files you can simply add the -deleteaction like so:

上面的命令将显示您将要删除的文件列表。要实际删除文件,您只需添加如下-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

If you would like to see what will remain you can invert the matches in the preview by adding !to the preview command (withoutthe -delete) like so:

如果你想看到什么仍将您可以通过添加反转预览比赛!的预览命令(没有-delete),像这样:

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

The output of this inverse match should be the same as the output you will see when listing the files after performing the delete unless errors occurred due to permissions problems or unwritable filesystems:

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

find path/to/files -type f

Explanation

解释

Here I will explain in some depth the options I chose and why:

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

I added -type fto restrict the matches to files-only; without that it will match non-files such as directories which you probably don't want. Also note that I put it at the beginning rather than the end because order of predicates can matter for speed; with -type ffirst it will execute the regex check against files-only instead of against everything... in practice it may not matter much unless you have lotsof directories or non-files. Still, it's worth keeping order of predicates in mind since it can have a significant impact in some cases.

我添加-type f将匹配限制为 files-only; 没有它,它将匹配非文件,例如您可能不想要的目录。还要注意,我把它放在开头而不是结尾,因为谓词的顺序对速度很重要;与-type f第一,除非你有这将执行对仅文件,而不是针对所有的正则表达式检查......在实践中它可能没有多大意义很多目录或非文件。尽管如此,记住谓词的顺序还是值得的,因为它在某些情况下会产生重大影响。

I use the case-insensitive-iregexoption as opposed to the case-sensitive -regexoption because I assumed that you wanted to use case-insensitive matching so it will include both .wmvand.WMVfiles.

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

You'll probably want to use extend POSIX regular expressionsfor simplicity and brevity. Unfortunately there is not yet a short-hand for -regextype posix-extended, but even still I would recommend using it because you can avoid the problem of having to add lots of \backslashes to escape things in longer, more complex regexes and it has more advanced (modern) features. The GNU implementation defaults to emacs-style regexeswhich can be confusing if you're not used to them.

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

The -deleteoption should make obvious sense, however sometimes people suggest using the slower and more complex -exec rm {} \;option, but usually that is because they are not aware of the safer, faster, and easier -deleteoption (and in rare cases you may encounter old systems with an ancient version of findthat does not have this option). It is useful to know that -execexists, but use -deletewhere you can for deleting files. Also, do not pipe |the output of findto another program unless you use and understand the -print0option, otherwise you're in for a world of hurt when you encounter files with spaces.

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

The path/to/filesargument I included explicitly. If you leave it out it will implicitly use .as the path, however it is safer (especially with a -delete) to state the path explicitly.

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

Alternate find Implementations

替代查找实现

Even though you said you're on a Linux system I will also mention the differences that you'll encounter with the BSD implementationswhich includes Mac OS X! For other systems (like older Solaris boxes), good luck! Upgrade to one of the more modern findvariants!

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

The main difference in this example is regarding regular expressions. The BSD variants use basic POSIX regular expressions by default. To avoid burdensome extra escaping in regexes required for basic-PRE you can take advantage of more modern features of extended-PRE by specifying the -Eoption with the BSD variant to achieve the same behavior as the GNU variant that uses -regextype posix-extended.

此示例中的主要区别在于正则表达式。默认情况下,BSD 变体使用基本的 POSIX 正则表达式。为了避免在 basic-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

Note in this case that the -Eoption comes beforethe path/to/fileswhereas the -regextype posix-extendedoption for GNU comes afterthe path.

注意,在这种情况下,该-E选项来之前path/to/files,而-regextype posix-extended对于GNU选项来的路径。

It is too bad that GNU does not yet provide a -Eoption (yet!); since I think it would be a useful option to have parity with the BSD variants I will submit a patch to findutilsto add this option and if it is accepted I will update this answer accordingly.

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

rm - Not Recommended

rm - 不推荐

Though I strongly recommend against using rm, I will give examples of how to accomplish more or less what your question specifically asked (with some caveats).

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

Assuming you use a shell with Bourne syntax (which is usually what you find on Linux system which default to the Bash shell) you can use this command:

假设您使用 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

If you use Bash and have extended globbing turned on with shopt -s extglobthen you can use Pattern Matching with Filename Expansion:

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

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

The +(pattern-list)extended globbing syntax will match one or more occurrences of the given patterns.

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

However, I strongly recommend against using rmbecause:

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

It is error-prone and dangerousbecause it is easy to accidentally put a space between the *'s which means you will delete everything; you cannot preview the result of the command ahead of time; it is fire-and-forget, so good luck with the aftermath.

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

It is non-portablebecause even if it happens to work in your particular shell, the same command line may not work in other shells (including other Bourne-shell variants if you are prone to using Bash-isms).

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

It has severe limitationsbecause if you have files that are nested in subdirectories or even just lots of files in a single directory, then you will quickly hit the limits on command line length when using file globbing.

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

I wish the rmcommand would just rmitself into oblivion because I can think of few places where I'd rather use rminstead of (even ancient implementations of) find.

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

回答by xesco

With Bash, you could first enable extglob option:

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

$ shopt -s extglob

$ shopt -s extglob

And do the following:

并执行以下操作:

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

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