删除目录中扩展名为pdf的文件以外的所有文件
我有一个包含以下内容的目录:
x.pdf y.zip z.mp3 a.pdf
我想删除除x.pdf
和a.pdf
之外的所有文件。 我如何从终端这样做? 没有子目录,因此不需要任何递归。
cd 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
使用bash
的扩展shell globbing,你可以删除任何扩展名为.pdf
以外的文件
rm -- *.!(pdf)
如@pts所述, --
字符表示任何命令选项的结束,在极少数名称以-
字符开头的文件中使命令安全。
如果你想删除没有任何扩展名的文件以及那些扩展名不是.pdf
,那么正如@DennisWilliamson所指出的,你可以使用
rm -- !(*.pdf)
默认情况下应启用扩展通配符,但如果不启用,则可以使用
shopt -s extglob
特别是如果你打算在脚本中使用它,重要的是要注意如果表达式与任何东西都不匹配(即如果目录中没有非pdf文件),那么默认情况下,glob将被未扩展地传递给rm
命令,导致错误
rm: cannot remove `*.!(pdf)': No such file or directory
您可以使用nullglob
shell选项修改此默认行为,但这有其自身的问题。 有关更全面的讨论,请参阅NullGlob – Greg的Wiki
删除到垃圾箱 :
$ cd $ 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: 以冒号分隔的模式列表,用于定义集合 路径名扩展忽略的文件名。
快速测试:
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 | grep pdf
ls | grep pdf
向我展示了我想要保留的文件。 嗯。 -
ls | grep -v pdf
ls | grep -v pdf
显示了相反的结果: 除了我想要保留的内容之外的所有内容。 换句话说,它显示了我想要删除的内容列表。 在做任何危险之前我都可以确认一下。 -
ls | grep -v pdf | xargs rm
ls | grep -v pdf | xargs rm
将该列表准确发送给rm
进行删除
正如我所说,我主要是因为它提供的安全性:对我来说不是偶然的。 另外两个优点:
- 它可以组合; 您可以根据需要使用
ls
或find
来获取初始列表。 你可以在缩小列表的过程中使用你喜欢的任何其他东西 – 另一个grep
,一些awk
或者其他什么。 如果您只需要删除名称中包含颜色的文件,则可以采用相同的方式构建它。 - 您可以将每个工具用于其主要目的。 我更喜欢使用
find
forfind
和rm
for removal,而不是必须记住find
接受-delete
标志。 如果你再次这样做,你可以组成替代解决方案; 也许不是rm
,你可以创建一个trash
命令,将文件移动到垃圾箱(允许“取消删除”)并管道到而不是rm
。 你不需要find
支持该选项,你只需要管道。
更新
请参阅@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
更长,但它非常有弹性,我确切地知道它的作用,而不必先研究它。
通过使用强大的file
命令,这个问题的答案(与我之前的答案相比)更好。
$ file -i abc.pdf abc: application/pdf; charset=binary
现在你的问题:
cd for var in ./* do if file -i "$var" | grep -q 'application/pdf\;' then echo "$var" fi done
for
命令的作用是以变量$var
的forms给出当前目录中的文件。 if-then
命令通过从file -i "$var" | grep -q 'application/pdf\;'
取出退出状态0
来输出pdf文件的名称 file -i "$var" | grep -q 'application/pdf\;'
命令,只有找到pdf文件才会使退出状态为0
。
rm $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')
警告! 最好先试试
ls -l $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')
rm -i -- !(*@(a|x).pdf)
读取为,删除所有不是a.pdf
或x.pdf
。
这通过使用2个扩展的globs来工作,外部的!()
来否定包含的glob,它本身要求glob必须在.pdf
后缀之前匹配一个或多个a
或x
模式。 请参阅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
便携式shell方式
$ ksh -c 'for i in ./*; do case $i in *.pdf)continue;; *)rm "$i";; esac;done'
几乎POSIX并兼容任何Bourne风格的shell( ksh
, bash
, dash
)。 非常适合便携式脚本,当你不能使用bash
的扩展shell globbing时。
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(".")))'