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


36

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

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

Answers:


66

这是您可能应该使用的简单解决方案:

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 不带 maxdepth -1

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

注意这一点!

您也可以使用设置其他值-maxdepth。例如,要删除当前目录及其子孙目录中的文件,但不能更深:

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

只要确保您从未把-delete其他表达式放在首位即可!您会看到我总是放在-delete最后。如果您将其放在开头,则将首先对其进行评估,然后将删除其下的所有文件.(包括未结尾的.gif文件和的深层sub-sub ... subdirect目录中的文件.)!

有关详细信息,请参阅手册页bashsh以及用于在这些例子中使用的命令:mvrm[,和(特别是)find


1
谢谢Eliah。我做了与您建议的第一种方法类似的操作,即将文件转换为其他格式,然后再转换回去。但这似乎不太理想且不干净。我喜欢您和@efthialex建议的第二种方法,现在正在使用它。谢谢!

1
@Marvis很高兴满足您的需求。顺便说一句,我已经使用扩展了有关另一个方法(或方法类)的信息,扩展了这个答案find
伊利亚·卡根

3
感谢您提供详细的答案find,确实是一个很好的发现。

1
为常识(move-delete-move)答案+1。
tu-Restate Monica-dor duh 2013年

Nit-pick:find*for循环相比,如何更好地处理其中包含的奇怪文件名?for循环可以*很好地处理文件,因为您已经使用了双引号。
Flimm

28

如果您使用的是bash(默认外壳程序),则extglobshell选项允许您使用扩展模式匹配语法。要启用它,请使用shopt内置命令:

shopt -s extglob

(我在.bashrc文件中包括了这一行。)

除其他事项外,它授予!()操作员访问权限,该操作员匹配不在括号内的任何模式。为了您的目的:

rm !(filename).gif

更多信息可在man bash“模式匹配”下找到。


1
很好的答案!它是针对bash的,因此可能不适合于便携式脚本编写,但对于交互式任务甚至某些脚本编写来说,这是最好的选择。它带有extglob必须启用的增加的复杂性,但是如果禁用它,则不会发生任何不好的情况(在这种情况下,这是行不通的)。即使我没有shopt -s extglob任何(或全局)配置文件,它似乎也是默认启用的。如果有一个简单的解释说明为什么它对我有用,那么您可能需要将其添加到此答案中。或者我可以发布一个新问题。
伊利亚·卡根

13

用+ + 打开终端并输入:CtrlAltT

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

-delete和之间的区别-exec rm -vf {} \;是,使用第二个选项,您将能够看到由于该-v标志而删除了哪些文件。该-delete选项无法做到这一点。(-name -delete将打印的文件名,但rm-v揭示如果每个文件被成功删除。)


1

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='[a-c].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,但它不会匹配.或者..,这样就不会影响这样的父目录。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.