删除具有特定扩展名的文件,但终端中的文件除外

我需要删除所有扩展名为.gif的文件,除了一个名为“filename.gif”的文件。 在终端中进行此操作的最佳方式是什么?

命令rm *.gif删除所有gif文件,包括文件filename.gif

这是你应该使用的简单解决方案:

 mv filename.gif filename.gif.keep rm *.gif mv filename.gif.keep filename.gif 

.keep扩展没有什么特别之处,这只是为了使文件名暂时不以.gif结尾。

如果您不能重命名该文件(并且存在重要的脚本情况):

 for X in *.gif; do if [ "$X" != "filename.gif" ]; then rm "$X" fi done 

或者你可以这样写得更短:

 for X in *.gif; do [ "$X" != "filename.gif" ] && rm "$X"; done 

您可能更喜欢使用find ; 它非常强大,您可能会认为它更具可读性,并且它可以更好地处理奇怪的文件名,其中包含*字符

 find . -maxdepth 1 -not -name 'filename.gif' -name '*.gif' -delete 

我已经使用了-not运算符来提高可读性,但是如果POSIX遵从性很重要 – 如果你没有使用GNU find,或者这是用于你想要重新分发给其他人或在各种系统上运行的脚本 -你应该使用! 运营商代替:

 find . -maxdepth 1 ! -name 'filename.gif' -name '*.gif' -delete 

关于find一个方便的事情是,您可以轻松地修改命令以区分大小写,以便它找到和删除扩展名为.GIF文件:

 find . -maxdepth 1 -not -name 'filename.gif' -iname '*.gif' -delete 

请注意,我使用-iname代替-name作为搜索模式*.gif但我还没有将它用于filename.gif 。 据推测,您确切地知道您的文件被调用了什么,并且-iname将匹配备用大写,而不仅仅是扩展名 ,而是文件名中的任何位置。

所有这些解决方案仅删除当前目录中立即存在的文件 。 它们不会删除当前目录中未包含的文件,也不会删除驻留在当前目录的子目录中的文件。

如果要删除当前目录中包含的所有文件(即包含在子目录中,以及这些子目录的子目录中,等等 – 当前目录或其任何后代中包含的文件),请使用find without maxdepth -1

 find . -not -name 'filename.gif' -name '*.gif' -delete 

小心这个!

您还可以使用-maxdepth设置其他值。 例如,要删除当前目录及其子孙的文件,而不是更深层次的文件:

 find . -maxdepth 3 -not -name 'filename.gif' -name '*.gif' -delete 

只要确保你在其他表达式之前永远不要放-delete ! 你会看到我总是把 – -delete 。 如果你把它放在开头,它将首先进行评估,然后评估所有文件. (包括不以.gif结尾的文件和深度子子目录中的文件. )将被删除!

有关更多信息 ,请参阅bashsh的手册页以及这些示例中使用的命令: mvrm[和(特别) find

如果您正在使用bash (默认shell),则extglob shell选项允许您使用扩展模式匹配语法。 要启用它,请使用shopt builtin命令:

 shopt -s extglob 

(我在.bashrc文件中包含该行。)

除此之外,它还授予对!()运算符的访问权限,该运算符匹配不在parens内部的任何模式。 为了您的目的:

 rm !(filename).gif 

有关详细信息,请参阅“模式匹配”下的man bash

使用Ctrl + Alt + T打开终端并键入:

 find . -type f -name "*.gif" -and -not -name "filename.gif" -exec rm -vf {} \; 

-delete-exec rm -vf {} \;之间的区别-exec rm -vf {} \; 是第二个选项,由于-v标志,您将能够看到哪些文件已被删除。 这是使用-delete选项无法完成的事情。 ( -name -delete将打印文件名,但带有-v rm显示每个文件是否已成功删除。)

GLOBIGNORE变量。 来自man bash

 GLOBIGNORE A colon-separated list of patterns defining the set of filenames to be ignored by pathname expansion. If a filename matched by a pathname expansion pattern also matches one of the patterns in GLOBIGNORE, it is removed from the list of matches. 

所以,一个简单的方法是将GLOBGINORE设置为有问题的文件名:

 $ touch {a,b,c,d}.png $ echo *.png a.png b.png c.png d.png $ GLOBIGNORE=c.png $ echo *.png a.png b.png d.png 

所以,在你的情况下:

 GLOBIGNORE=filename.gif; rm *.gif 

当然,由于GLOBIGNORE包含模式,因此只要您想要排除模式,就可以使用它:

 $ GLOBIGNORE='[ac].png'; echo *.png d.png $ touch bd.png; GLOBIGNORE='?.png'; echo *.png bd.png 

GLOBIGNORE一个优点(?!)是自动排除它...来自匹配,它启用dotglob

 The GLOBIGNORE shell variable may be used to restrict the set of file‐ names matching a pattern. If GLOBIGNORE is set, each matching filename that also matches one of the patterns in GLOBIGNORE is removed from the list of matches. The filenames ``.'' and ``..'' are always ignored when GLOBIGNORE is set and not null. However, setting GLOBIGNORE to a non-null value has the effect of enabling the dotglob shell option, so all other filenames beginning with a ``.'' will match. To get the old behavior of ignoring filenames beginning with a ``.'', make ``.*'' one of the patterns in GLOBIGNORE. The dotglob option is disabled when GLOBIGNORE is unset. 

因此,删除目录中所有文件和文件夹的简单方法是:

 GLOBIGNORE=.; rm -r * 

*将匹配以.开头的文件名. ,因为GLOBIGNORE启用了dotglob ,但它不匹配... ,所以你不会那样影响父目录。