【问题标题】:Using "find … -delete" to remove image files only from special subdirectories使用“find ... -delete”仅从特殊子目录中删除图像文件
【发布时间】:2023-03-24 06:11:01
【问题描述】:

我需要从不需要的图像中清除我的音乐收藏中的一些子目录。我正在使用 Ubuntu 14.04 和/或 Linux Mint 17.2 以及使用 find 命令的 bash shell 脚本。

目录结构(最小示例)如下:

Tagged
  Artist #1
    Artist #1 - An Album
      Artist #1 - A Track.flac
      cover.jpg
      something.png
    Artist #1 - [compilations]
      Artist #1 - A Track.flac
      cover.jpg
      something.png
  Artist #2
    Artist #2 - Another Album
      Artist #2 - A Track.mp3
      cover.jpg

在以“[compilations]”结尾的子文件夹中,我想删除所有类型的 jpeg 和/或 png 图像(因为标记软件错误地将它们放在那里)。任何碰巧在普通“相册”文件夹中的图像我也希望保留。

根据我的目录结构,名称中带有“[compilations]”的文件夹只能分别出现在“Artist”文件夹的下方;所以最多两层深。

我想出了以下查找命令:

$ cd Tagged
$ find . -maxdepth 2 -type d -name '*\[compilations\]' -exec find {} -type f -iname '*.jp*g' -or -iname '*.png' -delete \;

这似乎需要一些时间,但文件 "./Artist #1/Artist #1 - [compilations]/cover.jpg""./Artist #1/Artist #1 - [compilations]/something.png" 仍然存在(以及所有其他图像文件)。

作为 Linux 的新手,我假设我使用 find-delete 选项犯了一个愚蠢的错误,因为以下命令(没有 -delete) 正确显示文件:

$ find . -maxdepth 2 -type d -name '*\[compilations\]' -exec find {} -type f -iname '*.jp*g' -or -iname '*.png' \;
./Artist #1/Artist #1 - [compilations]/cover.jpg
./Artist #1/Artist #1 - [compilations]/something.png

所以这是我的问题:

  • 为什么 -delete 不起作用?
  • 对于路径和文件名中的空格、全局字符和外来字符等“夸张”,此命令真的安全吗?
  • 我将如何重写上述命令,仍然使用 bashfind
  • 能否优化命令(重新速度、安全、嵌套查找)?

在实际集合中,该命令必须遍历16899个文件夹,几乎所有文件夹都包含空格和外来字符(如捷克语、俄语、日语、希腊语、德语……),所以它必须是健壮的。

提前感谢您的任何见解和启发!

【问题讨论】:

  • find 命令中包含find 命令很奇怪...无论如何,您的删除仅适用于-iname '*.png' 谓词,因为您错过了一些分组。要检查会发生什么,请将 -delete 谓词替换为 -print 谓词。你会看到find 错过了所有的jpg。使用分组:\( -iname '*.jp*g' -or -iname '*.png' \)
  • @gniourf_gniourf 我真的想不出用一个find 命令来做到这一点的方法。我认为find-from-find 是正确的方法。不过,您对分组很了解;您应该将其发布为答案。
  • 感谢 gniourf_gniourf!我只是想出了同样的想法,经过更多的实验。是的,请把它作为答案发布,我很高兴接受你的而不是我的 ;-)

标签: linux bash shell ubuntu-14.04 linux-mint


【解决方案1】:

经过一些实验,我认为我的错误在于没有将 OR'ed 部分 放在括号中——似乎 find 使用了 -delete 仅在最后一个OR的右侧,即试图删除'*.png'。唉,我几乎所有的封面图片都是“*.jpg”,所以我认为它根本不起作用!

所以我认为更正的命令应该是:

$ find . -depth -maxdepth 2 -type d -name '*\[compilations\]' -exec find {} -type f \( -iname '*.jp*g' -or -iname '*.png' \) -delete \;

它似乎在我上面的测试用例上正常工作。

尽管如此,一些确认会很好。可能是我其他问题的一些答案,仅供参考和学习。 谢谢!

【讨论】:

    【解决方案2】:

    您的-delete 谓词仅适用于

    -iname '*.png'
    

    谓词,因为你错过了分组:当你给 find 以下内容时:

    -type f -iname '*.jp*g' -or -iname '*.png' -delete
    

    由于布尔运算符的优先级,find 理解:

    \( -type f -iname '*.jp*g' \) -or \( -iname '*.png' -delete \)
    

    要解决此问题,请使用:

    -type f \( -iname '*.jp*g' -or -iname '*.png' \) -delete
    

    我建议您尝试将-delete 替换为-print:您将看到-delete 适用于什么!

    现在,关于您的嵌套find:由于目录树的结构(您的文件只有深度3),您应该只能处理find 的一个实例:

    find -maxdepth 3 -path '*/*\[compilations\]/*' \( -iname '*.jp*g' -o -iname '*.png' \) -type f -print
    

    (我用-print代替-delete,这样你就可以在使用-delete执行命令之前检查它)。

    【讨论】:

    • 感谢您解释@gniourf_gniourf!仅使用一个 find 听起来是个好主意——但是,现实生活更加复杂。当使用诸如find /home/$USER/Musik/Tagged/ -maxdepth 3 -path '*/*\[compilations\]/*' \( -iname '*.jp*g' -o -iname '*.png' \) -type f -print 之类的东西从其他地方调用时,您提供的路径是否仍然有效?抱歉问了一个愚蠢的问题,我以前从未使用过 -path ......仍然需要学习很多东西! :-)
    • @Moonbase 是的,它会起作用的! (试试看,-print 而不是-delete 使命令无害)。但请引用您的变量扩展:"/home/$USER/Musik/Tagged"(带双引号)。
    • 再次干杯,刚刚试了一下,效果很好。我想不嵌套 find 也会快得多,稍后会在真正的集合上计时。感谢您对 $USER 部分进行引用的提示……我没有没有“奇怪”的用户名,但你是对的 - 始终保持安全! :-)
    • 对于那些感兴趣的人:在总共 16899 个文件夹的音乐收藏中,“嵌套查找”耗时 3.285 秒,而 gniourf_gniourf 的解决方案(仅查找一个)仅耗时 0.324 秒! (用于测量的实时时间。)哇。非常感谢。
    猜你喜欢
    • 2021-05-29
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    • 2020-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多