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


50

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

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

我想删除除x.pdf和以外的所有文件a.pdf。我如何在终端上执行此操作?没有子目录,因此不需要任何递归。

Answers:


63
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意味着删除它。

注意:此命令将删除当前目录以及所有子目录中的所有文件(pdf文件除外,但包括隐藏文件)。!必须在之前-name。只-name将仅包含.pdf,而-iname将同时包含.pdf.PDF

要仅在当前目录而不是子目录中删除,请添加-maxdepth 1

find . -maxdepth 1 -type f ! -iname "*.pdf" -delete

感谢您的回答。您能帮助我稍微了解一下语法吗?.意思是“和”?!表示“除外” -name表示您要通过名称参数排除,然后-delete在找到后采取的措施?因此,它将查找除“ * .pdf”以外的所有内容并将其删除?还是我误会了?
jessenorton 2014年

.表示当前目录。!表示将除.pdf末尾的文件外的所有文件都取走。-delete意味着删除它。我现在清楚了吗?
爱德华·托瓦尔兹

@terdon Starkers说没有子目录。请病态编辑我的答案以更广泛
爱德华·托瓦尔兹

+1您应该已包含-maxdepth 1开始的参数。然后建议删除该参数,以防有人要递归删除。
TulainsCórdova'14

3
引起了我的注意,我们应该使用-iname而不是-name,否则带有.PDF扩展名的文件将会通过。
muru

43

随着bash“s扩展外壳通配,你可以删除比其他任何扩展的文件.pdf使用

rm -- *.!(pdf)

正如@pts所指出的那样,--字符表示任何命令选项的结尾,在名称以-字符开头的文件很少见的情况下,使命令安全。

如果您要删除不带任何扩展名的文件以及扩展名为以外的文件.pdf,则可以使用@DennisWilliamson指出的方法

rm -- !(*.pdf)

默认情况下应启用扩展的globing,但如果不启用,则可以使用

shopt -s extglob

特别是如果您打算在脚本中使用此功能,则需要特别注意的是,如果表达式不匹配任何内容(例如,如果目录中没有非pdf文件),则默认情况下,该glob将不扩展地传递给rm命令,导致类似的错误

rm: cannot remove `*.!(pdf)': No such file or directory

您可以使用nullglobshell选项修改此默认行为,但是有其自身的问题。有关更详尽的讨论,请参见NullGlob-Greg的Wiki


更好地处理IMO。
塔卡特2014年

没有扩展名的文件呢?FWIW,在zsh中是rm *~*.pdf
EmilJeřábek,2014年

1
我将圆点放在括号内。
丹尼斯·威廉姆森

4
啊,星号也应该放在里面:!(*.py)。同样,大概,如果OP仅希望保留“ .pdf”文件,则也应删除没有扩展名的文件,并且不要忽略它们。
丹尼斯·威廉姆森

1
这种方法比公认的答案更简单,更整洁。
彼得

18

删除至垃圾箱

$ cd <the directory you want>
$ gvfs-trash !(*.pdf)

或通过mv命令(但这样你不能从废纸篓恢复它,因为它不.trashinfo信息记录,所以这意味着你移动你的文件到目的地属于按照以下)。

mv !(*.pdf) ~/.local/share/Trash/files

6
这种方法比直接使用更加安全rm
赛斯

14

最简单的方法:在某处创建另一个目录(如果您只是在一个目录中删除而不是递归删除,则它甚至可以是子目录);将所有.pdf文件移到那里;删除其他所有内容;将pdf移回;删除中间目录。

快速,轻松,您可以确切地看到自己在做什么。只需确保中间目录与您要清理的目录位于同一设备上,即可对移动进行重命名而不是复制!


4
+1再次提供对新手用户有意义的评论,几乎可以肯定不会导致无意中删除文件。
trognanders 2014年

4

使用bash的GLOBIGNORE:

GLOBIGNORE=x.pdf:a.pdf
rm *
unset GLOBIGNORE

从bash的手册页中:

全球:

            以冒号分隔的模式列表,用于定义集合
            路径名扩展将忽略的文件名数量。

快速测试:

mkdir /tmp/foooooo
cd /tmp/foooooo
touch x.pdf y.zip z.mp3 a.pdf
GLOBIGNORE=x.pdf:a.pdf
ls -1 *

输出:

压缩文件
mp3

3

注意并撰写:使用xargs

我喜欢这种方法,因为它让我非常小心:编写一种方法来仅显示我要删除的文件,然后将其发送给rmusing xargs。例如:

  • 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命令,该命令将文件移至垃圾箱(允许“取消删除”)并通过管道代替rm。您不需要find支持该选项,只需将其传递给它即可。

更新资料

请参阅@pabouk的评论,以了解如何修改此格式以处理某些极端情况,例如文件名中的换行符,文件名my_pdfs.zip等。


4
我在这里注意到了三个问题:a)它将排除pdf名称中包含任何位置的任何文件。--- b)如果后缀中的任何字母均为大写,它将删除PDF文件。--- c)使用的输出不是一个好主意ls。它不适用于包含换行符的文件名。某些ls替换特殊字符的实现,例如tab by ?。---最好使用:find -maxdepth 1 -print0。(不要这么短ls:) -----解决a)和b)使用grep -vi '\.pdf$'---完整(但仅GNU)解决方案:find -maxdepth 1 -print0 | grep -viz '\.pdf$' | xargs -0 rm
pabouk 2014年

1
我了解您将解决方案视为具有多个手动迭代的“交互式”过程,但是检查对于一长串文件几乎不可用,并且上述问题很容易引起错误。
pabouk 2014年

1
@pabouk好点;现实世界总是使事情复杂化,您的更正会有所帮助。:)但是我仍然认为这种整体方法是最好的。如果有太多文件无法直观地确认所有内容,则| head -20至少可以查看其外观是否大致正确,而如果只是rm my_pattern,您就没有机会发现大错误。
内森·朗

1
您也可以先找到文件,再删除它们,省去-delete键,仅用于find . -type f ! -name "*.pdf"打印到控制台,或通过管道传输到更少文件或文件。[然后通过管道将xargs传递到rm,如pabouk的注释一样(使用-print0 | ... -0表示奇怪的文件名)]
Xen2050 2014年

3

我通常通过交互式Python解释器解决此类问题:

mic@mic ~ $ python
>>> import os
>>> for f in os.listdir('.'):
...   if not f.endswith('.pdf'):
...     os.remove(f)

它可能比使用find或的单线更长xargs,但它具有极强的弹性,而且我确切地知道它的作用,而无需首先研究它。


对于那些对每条线越来越紧张的人,我们可以将其合并为一:for item in [f for f in os.listdir('.') if not f.endswith('.pdf')]: os.remove(item)
Jacob Vlijm 2014年

python -c "import os; for f in os.listdir('.'): if not f.endswith('.pdf'): os.remove(f)"
mic_e 2014年

[os.remove(f) for f in os.listdir('.') if not f.endswith('.pdf')]
mic_e 2014年

真好!第二个给我一个语法错误,不明白为什么。
Jacob Vlijm 2014年

奇怪; 它可以在我的系统上与python 3.4和python 2.7一起使用。
mic_e 2014年

2

更好的答案(与我以前的答案相比)是使用功能强大的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命令的工作是以变量的形式给当前目录中的文件$varif-then命令通过获取0from file -i "$var" | grep -q 'application/pdf\;'命令的退出状态来输出pdf文件的名称,0只有找到pdf文件时,它才会给出退出状态。



1
rm -i -- !(*@(a|x).pdf)

读取为,删除不是a.pdf或的所有文件x.pdf

这通过使用2个扩展!()的glob 起作用,外部用来否定所包含的glob,这本身要求glob必须匹配后缀之前的一个或多个ax模式.pdf。参见glob#extglob

$ ls -a
.dotfile1 .dotfile2 a.pdf x.pdf y.zip z.mp3

$ echo -- !(a.pdf)
-- x.pdf y.zip z.mp3

$ echo -- !(x.pdf)
-- a.pdf y.zip z.mp3

$ echo -- !(a.pdf|x.pdf)
-- y.zip z.mp3

$ echo -- !(@(a|x).pdf)   # NOTE.that this matches the .dotfiles* as well
-- . .. .dotfile1 .dotfile2 y.zip z.mp3

$ echo -- !(*@(a|x).pdf)  # but this doesn't
-- y.zip z.mp3

$ echo rm -i -- !(*@(a|x).pdf)
rm -i -- y.zip z.mp3

1

便携式外壳方式

$ ksh -c 'for i in ./*; do case $i in *.pdf)continue;; *)rm "$i";; esac;done'

几乎POSIX与任何的Bourne风格的shell兼容(kshbashdash)。非常适合可移植脚本以及无法使用bash的扩展外壳程序。

perl:

$ perl -le 'opendir(my $d,"."); foreach my $f (grep(-f && !/.pdf/ , readdir($d))){unlink $f};closedir $d'                                                             

或稍微清洁一点:

$ perl -le 'opendir(my $d,"."); map{ unlink $_ } grep(-f "./$_" && !/.pdf/ , readdir($d));closedir $d'

替代python

python -c 'import os;map(lambda x: os.remove(x), filter(lambda x: not x.endswith(".pdf"),os.listdir(".")))'

0

小心要删除的内容!

在尝试删除之前,对其进行测试的一种安全方法是先使用进行测试ls,因为某些未捕获的行为可能会删除不需要的文件。您可以直接在目录外部执行此操作。ls与相似rm,因此:

ls sub/path/to/files/!(*.pdf)

这将列出

y.zip
z.mp3

现在,您可以看到要删除的内容并可以安全地删除它们:

rm sub/path/to/files/!(*.pdf)

就是这样。您可以使用通配符*来更具选择性,例如仅保留编程课程文档:

rm sub/path/to/files/!(*programming*)
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.