我有档案文件:
./aaa
./bbb
./c/ccc
./d/ddd
我有另一个目录,其中包含相同的文件和其他目录。
./aaa
./bbb
./c/ccc
./d/ddd
./to-remove-1
./c/to-rem-ove-2
我需要删除第一个列表中没有的所有文件。
P.S。实际上,第一个列表是由命令find /some/dir/ -type f > somefile
创建的。所以我们有另一个目录。但是我正在寻找一个文件。
答案 0 :(得分:4)
要比较的目录是A
和B
,其中"额外"正在从B
删除文件:
$ (cd A && find .) > tmp.txt
$ cd B && find . >> ../tmp.txt
$ sort ../tmp.txt | uniq -u | xargs rm
$ rm ../tmp.txt
$ (cd B && { (cd ../A && find .) && (find .) } | sort | uniq -u | xargs rm)
这可以避免使用命令分组来使用临时文件。请注意,如果您的文件名中包含空格,则无法使用。见"警告"下方。
uniq
,find
,sort
和xargs
。 uniq -u
将从文件中删除所有重复的行。例如,我们可以使用find
和sort
将目录结构缩减为以下内容:
.
.
./c
./c
./c/ccc
./c/ccc
./c/to-rem-ove-2
./d
./d
./d/ddd
./d/ddd
./to-remove-1
有了这个,uniq -u
给了我们:
./c/to-rem-ove-2
./to-remove-1
您可以将其导入xargs
并使用rm
删除文件。例如... | uniq -u | xargs rm
。
我们有以下目录结构:
$ tree .
.
├── A
│ ├── c
│ │ └── ccc
│ └── d
│ └── ddd
└── B
├── c
│ ├── ccc
│ └── to-rem-ove-2
├── d
│ └── ddd
└── to-remove-1
我们可以使用find
命令列出所有目录。
$ find .
.
./B
./B/to-remove-1
./B/c
./B/c/ccc
./B/c/to-rem-ove-2
./B/d
./B/d/ddd
./A
./A/c
./A/c/ccc
./A/d
./A/d/ddd
我们不想拥有uniq
的主要目录,所以我们会这样做
cd
在运行find
之前进入每个目录,并将所有文件的列表保存到临时文件tmp.txt
。
$ (cd A && find .) > tmp.txt
$ (cd B && find .) >> tmp.txt
由于uniq -u
对已排序的文件进行操作(重复的行必须
彼此相邻),我们必须使用tmp.txt
对sort
进行排序。
$ sort tmp.txt | uniq -u
./c/to-rem-ove-2
./to-remove-1
我们现在可以使用xargs
删除"额外"来自B
的文件。
$ cd B
$ sort ../tmp.txt | uniq -u | xargs rm
文件现已消失:
$ find .
.
./c
./c/ccc
./d
./d/ddd
xargs -I {} rm {}
而不是普通xargs rm
来确保命令不起作用
如果文件名中有空格,那就错了。再次使用" vanilla" xargs rm
甚至不会删除目录
虽然它们列在find
命令的输出中。如果你有
e
下B
下的目录A
(因此应该是rm: cannot remove ‘./e’: Is a directory
删除),您将收到类似
rm -r
如果你想保留这些目录,你可以忽略它
错误。如果您需要删除它们,可以使用rm
sort -r
。如果您这样做,最好将它与(cd B && { (cd ../A && find .) && (find .) } |
sort -r | uniq -u | xargs -I {} rm -r {})
结合使用,以便在目录之前删除目录中的文件(如有必要)。如果您没有进行此更改,则不会更改功能,但可能会出现"错误"发布时不应该。
包含所有这些更改的整个命令是
GetMetaData = False
答案 1 :(得分:3)
在Linux上(使用GNU实用程序)
cd "/other/dir/"
# Consider using -xtype f to also include *symlinks* to files.
find . -type f -print0 |
grep -Fxvz -f <(cd "/some/dir" && find . -type f) |
xargs -0 echo rm
在BSD / OSX上
cd "/other/dir/"
find . -type f |
grep -Fxv -f <(cd "/some/dir" && find . -type f) |
tr '\n' '\0' | xargs -0 echo rm
符合POSIX标准的变体 - 较慢
cd "/other/dir/"
find . -type f |
grep -Fxv -f <(cd "/some/dir" && find . -type f) |
xargs -I {} echo rm {}
以上解决方案执行干运行;删除echo
以执行实际删除
此外,不使用someFile
命令中的-f someFile
作为grep
,而是使用动态创建参考文件列表的进程替换:-f <(cd "/some/dir" && find . -type f)
;这项工作需要bash
,而不是sh
请注意,type -f
仅匹配常规文件,而符号链接与文件不匹配。 GNU Find提供-xtype -f
以匹配后者。
find . -type f
列出当前目录子树中的所有(常规)文件; -print0
输出以NUL(零字节,0x0
)而不是换行符终止的每个路径。grep -Fxv
排除(-v
)字面上(-F
)和完全(-x
)与process substitution输出中的一行相匹配的所有输入行创建参考文件列表(-f <(...)
) - 换句话说:它只输出参考列表中不存在的那些输入行。-z
(--null-data
)选项将输入分为NUL字节而不是换行符 - 假设输入是NUL分隔的。xargs ... rm
将通过stdin传递的输入路径转换为命令行参数,以传递给rm
。
rm
调用(因为单个命令行上的许多路径都会传递给rm
) ,所有输入路径作为参数传递。rm
必须每个路径调用一次。-f
的引用列表必须 be 基于行按预期工作。即使选项--null-data
存在,GNU Grep也要求传递给-f
的文件中的搜索词是换行符 - 分离 - NUL分离不起作用。tr '\n' '\0'
用NUL替换所有换行符,当xargs -0
调用xargs
时,它与rm
一起保留每个输入行作为自己的参数。
-z
选项,但其目的非常不同。 BSD Grep的 no 等同于GNU Grep的-z
(--null-data
)选项,使用后者是保留嵌入式换行符的唯一方法输入xargs -I {} rm {}
将每个输入行视为单参数传递给rm
- 缺点是必须调用rm
每行一次(路径)
使用仅限POSIX的功能,您不能同时传递带有嵌入空格或制表符的多个参数,除非您用引号括住每个标记,但这带来了自己的挑战。答案 2 :(得分:0)
comm <(sort file1) <(sort file2) -13 | xargs -r rm