我刚刚使用 Recuva 和 Photorec 从意外格式化的驱动器中恢复了一些数据。结果自然是驱动器在其生命周期内存在的所有完整文件都被恢复了。这意味着我想要删除数以万计的小图标图像(PNG 和 JPG)——假设任何小于 100 x 100px 的图像。
有解决方案出去那里,但它们都相当复杂,甚至最简单的也依赖于通过几个外部程序进行管道传输并rm
执行实际删除。这并不理想,因为当经常做某事时,bash
我总是更喜欢每次都能记住并在命令行中输入的单行代码。
在 GNU 更加成熟的时代find
,-delete
难道真的没有办法完全甚至大部分在find
其内部完成这些工作吗?
编辑:如果find
不行的话,我也很乐意使用任何其他 GNU 工具。
答案1
在 GNU 更加成熟的时代
find
,-delete
难道真的没有办法完全甚至大部分在find
其内部实现这一目标吗?
find
不用于读取图像(元)数据(比较“DOTADIW”)。要执行任意测试,请使用-exec
测试 (例子),然后-delete
。它可能是这样的:
find . -type f -exec some_program -with -options -that -test -dimensions {} \; -delete
当且仅当返回文件的some_program
退出状态,才会启动该文件。0
-delete
对于更复杂的测试,你可能需要一个内壳:
find . -type f -exec sh -c 'shell-code "$1" | with-pipes && con-di-tio-nals -and -such' arbitrary-name {} \; -delete
当且仅当sh
返回退出状态,才会启动。0
-delete
一大优点:你可以安全地做到这一点即使文件名中有换行符、空格或特殊字符。代码非常健壮。
一个很大的缺点:-exec … \;
会运行一个some_program
每个文件。或者每个文件一个、和sh
。shell-code
创建额外的进程成本很高,因此这种方法可能效果不佳。with-pipes
con-di-tio-nals
为了减轻这个缺点,你可以一次将更多文件名传递给内壳。这就是这个答案确实(代码已经调试过):
find . -iname "*.jpg" -type f -exec bash -c 'for i; do size=($(identify -format "%w %h" "$i")); (( size[0] < 300 || size[1] < 300 )) && rm -v "$i"; done' remove-files {} +
注意-exec … +
,此处的测试不会触发-delete
。每个 shell 进程处理多个文件并返回单个退出状态,因此它不是用于单个文件的有用测试。相反,rm
是在 shell 内有条件地调用的。
identify
每个文件仍会有一个,rm
每个要删除的文件也会有一个。另一方面,bash
每个许多文件。为了获得良好的性能,您应该优先选择 shell 内置命令、shell 算法和 shell 语法,而不是外部可执行文件。这种方法仍然可以安全、可靠地处理文件名。
有一些工具可以用单一流程测试多个文件。例如:
exiftool -q -r -if '$ImageHeight < 100' -if '$ImageWidth < 100' -p '$Directory/$FileName' .
(这是exiftool
来自libimage-exiftool-perl
Debian 的软件包。解决方案取自这个答案。
请注意,此特定命令不仅限于“PNG 和 JPG”。
命令印刷结果类似find . … -print
。然后您可以通过管道xargs
调用rm
。常见问题关于管道路径作为文本应用,我不确定是否可以做出exiftool
类似的行为find . … -print0
。
因此,虽然该解决方案在查找文件和打印其路径时表现良好,但它并不是在没有人工监督的情况下实际删除它们的最强大的方法。