当前位置: 首页>>技术问答>>正文


删除目录中扩展名为pdf的文件以外的所有文件

, ,

问题描述

我有一个包含以下内容的目录:

x.pdf
y.zip
z.mp3
a.pdf

我想删除除x.pdfa.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

第三种解决思路

Delete to trash

$ 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 *。另外两个优点:

  • 它可以组合;您可以根据需要使用lsfind获取初始列表。您可以在缩小列表的过程中使用您喜欢的任何其他内容 – 另一个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)

它可能比使用findxargs的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的退出状态。

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/1571.html,未经允许,请勿转载。