当前位置: 首页>>技术问答>>正文


查找不包含文件的目录

ubuntuer 技术问答 , , 去评论

问题描述

是的,我正在整理我的音乐。我在下面的口头禅中把所有东西都精美地安排好了:/Artist/Album/Track - Artist - Title.ext如果有的话,封面就在/Artist/Album/cover.(jpg|png)中。

我想扫描所有second-level目录并找到没有封面的目录。在第二级,我的意思是我不在乎/Britney Spears/是否没有cover.jpg,但我会关心/Britney Spears/In The Zone/没有。

不要担心cover-downloading(明天对我来说这是一个有趣的项目)我只关心inverse-ish关于inverse-ish find示例的光荣bash-fuiness。

最佳解决方法

案例1:您知道要查找的确切文件名

使用findtest -e your_file检查文件是否存在。例如,您查找其中没有cover.jpg的目录:

find base_dir -mindepth 2 -maxdepth 2 -type d '!' -exec test -e "{}/cover.jpg" ';' -print

虽然这是区分大小写的。

案例2:你想要更灵活

您不确定这种情况,扩展名可能是jPgpng ……

find base_dir -mindepth 2 -maxdepth 2 -type d '!' -exec sh -c 'ls -1 "{}"|egrep -i -q "^cover\.(jpg|png)$"' ';' -print

说明:

  • 您需要为每个目录生成一个shell sh,因为使用find时无法进行管道连接

  • ls -1 "{}"只输出find目前正在遍历的目录的文件名

  • egrep(而不是grep)使用扩展的正则表达式; -i使搜索不区分大小写,-q使其省略任何输出

  • "^cover\.(jpg|png)$"是搜索模式。在这个例子中,它匹配例如cOver.pngCover.JPGcover.png。必须转义.,否则表示它匹配任何字符。 ^标志着该行的开始,$结束

egrep的其他搜索模式示例:

用以下代码替换egrep -i -q "^cover\.(jpg|png)$"部件:

  • egrep -i -q "cover\.(jpg|png)$":也符合cd_cover.pngalbum_cover.JPG

  • egrep -q "^cover\.(jpg|png)$":匹配cover.pngcover.jpg,但不匹配Cover.jpg(区分大小写未关闭)

  • egrep -iq "^(cover|front)\.jpg$":例如匹配front.jpgCover.JPG但不是Cover.PNG

有关这方面的更多信息,请查看Regular Expressions

次佳解决方法

简单,它发生了。以下内容获取带有封面的目录列表,并将其与所有second-level目录的列表进行比较。 “files”中出现的行被抑制,留下需要覆盖的目录列表。

comm -3 \
    <(find ~/Music/ -iname 'cover.*' -printf '%h\n' | sort -u) \
    <(find ~/Music/ -maxdepth 2 -mindepth 2 -type d | sort) \
| sed 's/^.*Music\///'

万岁。

笔记:

  • comm的论点如下:

    • -1抑制file1特有的行

    • -2抑制file2特有的行

    • -3会抑制两个文件中出现的行

  • comm只接受文件,因此是kooky <(...)输入法。这通过真实的[临时]文件管理内容。

  • comm需要排序输入或它不起作用,find不能保证订单。它也需要是独一无二的。第一个find操作可以找到cover.*的多个文件,因此可能存在重复的条目。 sort -u迅速将那些降至一个。第二个发现总是独一无二的。

  • dirname是一个方便的工具,用于获取文件的目录而无需使用sed(等)。

  • findcomm的输出都有点乱。最后的sed可用于清理,因此您可以使用Artist/Album。这对您来说可能是也可能不合适。

第三种解决方法

使用globbing比使用find更好地解决这个问题。

$ cd ... # to the directory one level above the album/artist structure

$ echo */*/*.cover   # lists all the covers

$ printf "%s\n" */*/*.cover # lists all the covers, one per line

现在假设你在这个漂亮的结构中没有迷路文件。当前目录仅包含艺术家子目录,并且仅包含专辑子目录。然后我们可以这样做:

$ diff  <(for x in */*/cover.jpg; do echo "$(dirname "$x")" ; done) <(printf "%s\n" */*)

<(...)语法是Bash进程替换:它允许您使用命令代替文件参数。它允许您将命令的输出视为文件。因此,我们可以运行两个程序,并获取它们的差异,而不将其输出保存在临时文件中。 diff程序认为它正在使用两个文件,但实际上它是从两个管道读取的。

产生右手输入到diffprintf "%s\n" */*的命令只列出了专辑目录。左手命令遍历*.cover路径并打印其目录名称。

测试运行:

$ find .   # let's see what we have here
.
./a
./a/b
./foo
./foo/bar
./foo/baz
./foo/baz/cover.jpg

$ diff  <(for x in */*/cover.jpg; do echo "$(dirname "$x")" ; done) <(printf "%s\n" */*)
0a1,2
> a/b
> foo/bar

Aha,a/bfoo/bar目录没有cover.jpg

有一些破损的案例,如默认情况下*如果没有匹配就扩展到自己。这可以通过Bash的set -o nullglob来解决。

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/1721.html,未经允许,请勿转载。