问题描述
我需要删除所有扩展名为.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
的一个方便之处是你可以轻松地修改case-insensitivity的命令,这样它就可以找到和删除扩展名为.GIF
的文件:
find . -maxdepth 1 -not -name 'filename.gif' -iname '*.gif' -delete
请注意,我使用-iname
代替-name
搜索模式*.gif
,但我还没有将它用于filename.gif
。据推测,您确切地知道您的文件被调用了什么,而-iname
将匹配备用大写,而不仅仅是扩展名,而是文件名中的任何位置。
所有这些解决方案仅删除当前目录中立即驻留的文件。它们不会删除当前目录中未包含的文件,也不会删除驻留在当前目录的子目录中的文件。
如果要删除当前目录中包含的所有文件(即包括在子目录中,以及这些子目录的子目录中,等等 – 当前目录或其任何后代中包含的文件),请使用不带maxdepth -1
的find
:
find . -not -name 'filename.gif' -name '*.gif' -delete
小心这个!
您还可以使用-maxdepth
设置其他值。例如,要删除当前目录及其子孙的文件,而不是更深层次的文件:
find . -maxdepth 3 -not -name 'filename.gif' -name '*.gif' -delete
只需确保在其他表达式之前永远不要放置-delete
!你会看到我总是将-delete
放在最后。如果你把它放在开头,它将首先被评估,并且.
下的所有文件(包括不以.gif
结尾的文件和.
的深sub-sub-sub …目录中的文件)将被删除!
有关详细信息,请参阅bash
和sh
的手册页以及这些示例中使用的命令:mv
,rm
,[
和(特别是)find
。
次佳解决办法
如果您使用的是bash
(默认shell),则extglob
shell选项允许您使用扩展模式匹配语法。要启用它,请使用shopt
内置命令:
shopt -s extglob
(我在.bashrc
文件中包含该行。)
除此之外,它还授予对!()
运算符的访问权限,该运算符匹配不在parens内部的任何模式。为了您的目的:
rm !(filename).gif
有关更多信息,请参见”Pattern Matching”下的man bash
。
第三种解决办法
使用Ctrl
+ Alt
+ T
打开终端并键入:
find . -type f -name "*.gif" -and -not -name "filename.gif" -exec rm -vf {} \;
-delete
和-exec rm -vf {} \;
之间的区别在于,使用第二个选项,由于-v
标志,您将能够看到哪些文件已被删除。这是使用-delete
选项无法完成的事情。 (-name -delete
将打印文件名,但带有-v
的rm
会显示每个文件是否已成功删除。)