使用 find 删除给定尺寸下的所有图像

使用 find 删除给定尺寸下的所有图像

我刚刚使用 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 每个文件。或者每个文件一个、和shshell-code创建额外的进程成本很高,因此这种方法可能效果不佳。with-pipescon-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-perlDebian 的软件包。解决方案取自这个答案

请注意,此特定命令不仅限于“PNG 和 JPG”。

命令印刷结果类似find . … -print。然后您可以通过管道xargs调用rm常见问题关于管道路径作为文本应用,我不确定是否可以做出exiftool类似的行为find . … -print0

因此,虽然该解决方案在查找文件和打印其路径时表现良好,但它并不是在没有人工监督的情况下实际删除它们的最强大的方法。

相关内容