问题描述
我有一个包含以下内容的目录:
x.pdf
y.zip
z.mp3
a.pdf
我想删除除x.pdf
和a.pdf
之外的所有文件。我如何从终端这样做?没有子目录,因此不需要任何递归。
最佳解决思路
cd <the directory you want>
find . -type f ! -iname "*.pdf" -delete
-
第一个命令将带您进入要删除文件的目录
-
第二个命令将删除除文件名中以
.pdf
结尾的文件之外的所有文件
例如,如果您的主文件夹中有一个名为temp
的目录:
cd ~/temp
然后删除文件:
find . -type f ! -iname "*.pdf" -delete
这将删除除xyz.pdf
之外的所有文件。
您可以将这两个命令组合到:
find ~/temp -type f ! -iname "*.pdf" -delete
.
是当前目录。 !
表示最后获取除.pdf
之外的所有文件。 -type f
仅选择文件,而不选择目录。 -delete
表示删除它。
注意:此命令将删除当前目录以及所有sub-directories中的所有文件(pdf文件除外,但包括隐藏文件)。 !
必须在-name
之前。简单地说,-name
仅包括.pdf
,而-iname
将包括.pdf
和.PDF
要仅在当前目录中删除而不在sub-directories中删除,请添加-maxdepth 1
:
find . -maxdepth 1 -type f ! -iname "*.pdf" -delete
次佳解决思路
使用bash
的扩展shell globbing,您可以删除除.pdf
之外的任何扩展名的文件
rm -- *.!(pdf)
如@pts所述,--
字符表示任何命令选项的结束,在极少数名称以-
字符开头的文件中使命令安全。
如果你想删除没有任何扩展名的文件以及那些扩展名不是.pdf
的文件,那么正如@DennisWilliamson指出的那样你可以使用
rm -- !(*.pdf)
默认情况下应启用扩展通配符,但如果不启用,则可以使用
shopt -s extglob
特别是如果你打算在脚本中使用它,重要的是要注意如果表达式与任何东西都不匹配(即如果目录中没有non-pdf文件),那么默认情况下,glob将被未扩展地传递给rm
命令,导致错误
rm: cannot remove `*.!(pdf)': No such file or directory
您可以使用nullglob
shell选项修改此默认行为,但这有其自身的问题。有关更详尽的讨论,请参阅NullGlob – Greg’s Wiki
第三种解决思路
$ cd <the directory you want>
$ gvfs-trash !(*.pdf)
或者通过mv
命令(但是这样您就无法从垃圾箱中恢复它,因为它不记录.trashinfo信息,因此这意味着您将文件移动到目标位置,如下所示)。
mv !(*.pdf) ~/.local/share/Trash/files
第四种思路
最简单的方法:在某处创建另一个目录(如果你只是在一个目录中删除,而不是递归,它甚至可以是一个子目录);将所有.pdf移到那里;删除其他一切;将pdf移回;删除中间目录。
快速,简单,您可以准确地看到您正在做的事情。只需确保中间目录与您正在清理的目录位于同一设备上,以便移动重命名,而不是复制!
第五种思路
使用bash的GLOBIGNORE:
GLOBIGNORE=x.pdf:a.pdf
rm *
unset GLOBIGNORE
从bash的手册页:
GLOBIGNORE:
A colon-separated list of patterns defining the set
of filenames to be ignored by pathname expansion.
快速测试:
mkdir /tmp/foooooo
cd /tmp/foooooo
touch x.pdf y.zip z.mp3 a.pdf
GLOBIGNORE=x.pdf:a.pdf
ls -1 *
输出:
y.zip
z.mp3
第六种思路
小心并撰写:使用xargs
这是我喜欢的方法,因为它让我非常小心:构建一种方法来显示我想要删除的文件,然后使用xargs
将它们发送到rm
。例如:
-
ls
向我展示了一切 -
ls | grep pdf
显示我想要保留的文件。嗯。 -
ls | grep -v pdf
显示了相反的结果:除了我想要保留的内容之外的所有内容。换句话说,它显示了我想要删除的内容列表。在做任何危险之前我都可以确认一下。 -
ls | grep -v pdf | xargs rm
将该列表准确发送到rm
以进行删除
正如我所说,我主要是因为它提供的安全性:对我来说没有意外的rm *
。另外两个优点:
-
它可以组合;您可以根据需要使用
ls
或find
获取初始列表。您可以在缩小列表的过程中使用您喜欢的任何其他内容 – 另一个grep
,某些awk
或其他任何内容。如果您只需要删除名称中包含颜色的文件,则可以采用相同的方式构建它。 -
您可以将每个工具用于其主要目的。我更喜欢使用
find
进行查找和rm
去除,而不是必须记住find
接受-delete
标记。如果你再次这样做,你可以组成替代解决方案;也许代替rm
,你可以创建一个trash
命令,将文件移动到废纸篓(允许”undeletion”)并管道到那个而不是rm
。你不需要拥有find
支持该选项,你只需管道它。
Update
请参阅@pabouk的注释,了解如何修改它以处理某些边情况,例如文件名中的换行符,my_pdfs.zip
等文件名等。
第七种思路
我通常从交互式Python解释器中解决这些问题:
mic@mic ~ $ python
>>> import os
>>> for f in os.listdir('.'):
... if not f.endswith('.pdf'):
... os.remove(f)
它可能比使用find
或xargs
的one-liner更长,但它非常有弹性,我确切地知道它的作用,而不必先研究它。
第八种思路
通过使用功能强大的file
命令,可以更好地回答(与我之前的回答相比)。
$ file -i abc.pdf
abc: application/pdf; charset=binary
现在你的问题:
cd <the directory you want to search in>
for var in ./*
do
if file -i "$var" | grep -q 'application/pdf\;'
then
echo "$var"
fi
done
for
命令的工作是以变量$var
的形式给出当前目录中的文件。 if-then
命令通过从file -i "$var" | grep -q 'application/pdf\;'
命令获取0
的退出状态输出pdf文件的名称,只有在找到pdf文件时才会给出0
的退出状态。