Это гораздо приятнее решать с помощью шатания, чем с помощью поиска.
$ 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Программа считает , что она работает с двумя файлами, но на самом деле это чтение из двух труб.
Команда , которая производит правильный вход руки в 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
Ага, то a/bи foo/barкаталогов нету cover.jpg.
Есть несколько случаев с разбитыми углами, например, которые по умолчанию *расширяются, если ничего не совпадают. Это можно решить с помощью Баш set -o nullglob.