删除具有特定扩展名的文件,但终端中的文件除外
我需要删除所有扩展名为.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
结尾的文件和深度子子目录中的文件.
)将被删除!
有关更多信息 ,请参阅bash
和sh
的手册页以及这些示例中使用的命令: mv
, rm
, [
和(特别) 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
,但它不匹配.
或..
,所以你不会那样影响父目录。