假设文件夹中/photo
有很多文件,例如
1.jpg
2.jpg
3.jpg
4.jpg
5.jpg
6.jpg
7.jpg
8.jpg
9.jpg
10.jpg
nodeletelist.txt
我在此文本文件中有一个文件名,其名称为不删除文件列表,例如
1.jpg
2.jpg
3.jpg
nodeletelist.txt
如何删除文件:
4.jpg
...
10.jpg
除了文件1.jpg
、2.jpg
、3.jpg
以及nodeletelist.txt
哪个nodeletelist.txt
?
答案1
你有 GNU 发现吗?
find photo -mindepth 1 -maxdepth 1 -regextype awk \! -regex ".*/($(tr '\n' '|' < photo/nodeletelist.txt)nodeletelist.txt)" -delete
这是通过使用tr(1)
和来实现的find(1)
。
- 将文件重定向到
tr
- 用竖线替换换行符,表示“OR”
- 从子 shell 返回
- 在末尾添加一个标记值,以防文件以换行符结尾。 (在本例中,我使用您的名称
nodeletelist.txt
作为哨兵,因此如果您使用此解决方案,则不需要在文件中包含文件名。) - 在目录中搜索正好位于下面一层的条目
photo
- 使用 awk 正则表达式来匹配上面步骤 1-4 返回的字符串
- 删除文件不是由正则表达式匹配(因为
!
表示“NOT”)
此处的标志-regextype
也可以设置为posix-extended
、egrep
、posix-egrep
、gnu-awk
或,posix-awk
因为此处所需的扩展语法适用于它们。默认的 findutils 正则表达式、posix-basic、emacs、sed 等不适用于此命令。
答案2
如果zsh
是一个选项,您可以定义一个 shell 函数来用作“全局限定符" 用于过滤 glob 中所有文件的列表*
,例如
% cmd() { ! grep -qF "$REPLY" ./nodeletelist.txt ; }
然后(从photo/
目录)
% ls
10.jpg 1.jpg 2.jpg 3.jpg 4.jpg 5.jpg 6.jpg 7.jpg 8.jpg 9.jpg nodeletelist.txt
% ls *(+cmd)
10.jpg 4.jpg 5.jpg 6.jpg 7.jpg 8.jpg 9.jpg
看起来不错,我们删除吧
% rm *(+cmd)
% ls
1.jpg 2.jpg 3.jpg nodeletelist.txt
可能有一种更有效的实现,首先将文件映射到数组中,然后测试是否$REPLY
是数组的元素。
答案3
对我来说,最简单且易于记住,并且也适用于很多文件(思想会在文件名中的换行符处中断,但如果你有的话,你将不得不考虑你的列表):
cd /photo
ls -1 | grep -v -x -f nodeletelist.txt | xargs -d "\n" -P 0 rm -f
如果目录中有其他内容(子目录或不同的文件,我不假设您在列表中包含您的txt),我会使用 find I 而不是 ls (find . -maxdepth 1 -type f -name "*.jpg"
例如)。
答案4
对于名称中没有空格的所述情况
rm $(join -v 1 <(ls *.jpg) <(sed '$ d' nodeletelist.txt))
假设文件nodeletelist.txt的最后一行实际读取nodeletelist.txt
如果没有,那么就
rm $(join -v 1 <(ls *.jpg) nodelete.txt)
但感觉不太优雅...