是的,我正在整理我的音乐。我已经按照以下口头禅将所有内容都安排得很好:/Artist/Album/Track - Artist - Title.ext如果存在,则封面位于/Artist/Album/cover.(jpg|png).
我想扫描所有的二级目录,找到那些没有封面的。第二级,我的意思是我不在乎/Britney Spears/没有cover.jpg,但我会在乎如果/Britney Spears/In The Zone/没有。
不要担心封面下载(明天对我来说这是一个有趣的项目)我只关心关于一个反向find例子的辉煌 bash-fuiness 。
pho*_*bos 94
使用findwithtest -e your_file检查文件是否存在。例如,您查找其中没有的目录cover.jpg:
find base_dir -mindepth 2 -maxdepth 2 -type d '!' -exec test -e "{}/cover.jpg" ';' -print
Run Code Online (Sandbox Code Playgroud)
虽然它区分大小写。
您不确定这种情况,扩展名可能是jPg,png...
find base_dir -mindepth 2 -maxdepth 2 -type d '!' -exec sh -c 'ls -1 "{}"|egrep -i -q "^cover\.(jpg|png)$"' ';' -print
Run Code Online (Sandbox Code Playgroud)
sh为每个目录生成一个 shell ,因为在使用时不可能进行管道传输findls -1 "{}"只输出find当前正在遍历的目录的文件名egrep( 而不是grep) 使用扩展的正则表达式;-i使搜索不区分大小写,-q使其省略任何输出"^cover\.(jpg|png)$"是搜索模式。在这个例子中,它匹配 eg cOver.png, Cover.JPGor cover.png。在.必须以其他方式逃脱它意味着它匹配任何字符。^标记行的开始,$结束egrep 的其他搜索模式示例:
将egrep -i -q "^cover\.(jpg|png)$"部分替换为:
egrep -i -q "cover\.(jpg|png)$": 也匹配cd_cover.png, album_cover.JPG...egrep -q "^cover\.(jpg|png)$": 匹配cover.png, cover.jpg, 但 NOT Cover.jpg(不关闭区分大小写)egrep -iq "^(cover|front)\.jpg$": 匹配 eg front.jpg,Cover.JPG但不匹配 Cover.PNG有关这方面的更多信息,请查看正则表达式。
Oli*_*Oli 13
很简单,它发生了。下面获取带有封面的目录列表,并将其与所有二级目录的列表进行比较。出现在两个“文件”中的行被抑制,留下需要覆盖的目录列表。
comm -3 \
<(find ~/Music/ -iname 'cover.*' -printf '%h\n' | sort -u) \
<(find ~/Music/ -maxdepth 2 -mindepth 2 -type d | sort) \
| sed 's/^.*Music\///'
Run Code Online (Sandbox Code Playgroud)
万岁。
笔记:
comm的论据如下:
-1 抑制文件 1 独有的行-2 抑制文件 2 独有的行-3 抑制出现在两个文件中的行comm只需要文件,因此古怪的<(...)输入法。这通过真正的 [临时] 文件来管理内容。
comm需要排序的输入,否则它不起作用并且find绝不保证订单。它也需要是独一无二的。第一个find操作可能会找到多个文件,cover.*因此可能会有重复的条目。sort -u迅速将这些归为一。第二个发现总是独一无二的。
dirname是一个方便的工具,无需求助于sed(et al)即可获取文件的目录。
find并且comm它们的输出都有些混乱。最后sed是清理东西,所以你只剩下Artist/Album. 这对您来说可能是也可能不是。
小智 9
使用 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
Run Code Online (Sandbox Code Playgroud)
现在假设您在这个漂亮的结构中没有杂散文件。当前目录只包含艺术家子目录,那些只包含专辑子目录。然后我们可以做这样的事情:
$ diff <(for x in */*/cover.jpg; do echo "$(dirname "$x")" ; done) <(printf "%s\n" */*)
Run Code Online (Sandbox Code Playgroud)
该<(...)语法是bash进程替换:它可以让你在一个地方文件参数的使用的命令。它允许您将命令的输出视为文件。所以我们可以运行两个程序,并获取它们的差异,而无需将它们的输出保存在临时文件中。该diff程序认为它正在处理两个文件,但实际上它正在从两个管道中读取。
产生右手输入命令diff,printf "%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
Run Code Online (Sandbox Code Playgroud)
啊哈,a/b和foo/bar目录没有cover.jpg.
有一些破碎的角落情况,例如默认情况下,*如果它不匹配任何内容,则会扩展到自身。这可以通过 Bash 的set -o nullglob.