Intereting Posts
Как установить программное обеспечение вручную? Есть ли накопитель Gmail? Могу ли я иметь двух пользователей в моей системе, играя в игры одновременно? Как легко изменить размер обоев для экрана? Есть ли подробная документация пользователя для KDE Plasma 5? Есть ли программное обеспечение для редактирования изображений, которое может открывать файлы Microsoft DirectDraw Surface в Ubuntu? unattended-updates отправляет вложение вместо текста Ubuntu сбой и перезапуск навсегда как я могу потратить минутные минуты? Измените пароль keyring после сброса пароля с помощью «passwd»: Ubuntu 13.10 Как изменить цвет фона Leafpad? (изменение .gtkrc недостаточно) Не удается прочитать текст в веб-формах, так как firefox использует темную тему по умолчанию Как называется приложение «Программное обеспечение» в Xubuntu Ubuntu 16.04 / 17.04 / 17.10 & CENTOS 6,7: мерцание экрана и случайное завершение работы (Lenovo Thinkpad T410) Идеи для моего проекта MSc и Google Summer of Code 2011

Найти каталоги, которые НЕ содержат файл

Да, я разбираюсь в своей музыке. У меня все прекрасно организовано в следующей мантре: /Artist/Album/Track - Artist - Title.ext и если он существует, обложка находится в /Artist/Album/cover.(jpg|png) .

Я хочу просмотреть все каталоги второго уровня и найти те, у которых нет обложки. На втором уровне, я имею в виду, мне все равно, если /Britney Spears/ не имеет cover.jpg, но мне все равно, если /Britney Spears/In The Zone/ не было.

Не беспокойтесь о загрузке обложки (для меня это забавный проект завтра). Меня волнует только славная бахишность об обратном примере find .

Случай 1: вы знаете точное имя файла для поиска

Используйте find с test -e your_file чтобы проверить, существует ли файл. Например, вы ищете каталоги, в которых нет cover.jpg :

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

Однако это чувствительно к регистру.

Случай 2: вы хотите быть более гибким

Вы не уверены в этом случае, а расширение может быть jPg , png

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

Объяснение:

  • Вам нужно создать оболочку sh для каждой директории, поскольку невозможно использовать трубопровод при использовании find
  • ls -1 "{}" выводит только имена файлов каталога, в настоящее время просматривается
  • egrep (вместо grep ) использует расширенные регулярные выражения; -i делает регистр поиска нечувствительным, -q делает его недействительным
  • "^cover\.(jpg|png)$" – шаблон поиска. В этом примере он соответствует, например, cOver.png , Cover.JPG или cover.png . . должен быть экранирован, иначе это означает, что он соответствует любому символу. ^ обозначает начало строки, $ end

Другие примеры шаблонов поиска для 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$" : соответствует, например, Cover.JPG , Cover.JPG но не Cover.PNG

Дополнительные сведения об этом см. В разделе Регулярные выражения .

Простой, это выясняется. Следующее получает список каталогов с обложкой и сравнивает это со списком всех каталогов второго уровня. Строки, которые отображаются в обоих файлах, подавляются, оставляя список каталогов, которые нуждаются в обложках.

 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 подавляет линии, уникальные для файла2
    • -3 подавляет линии, которые появляются в обоих файлах
  • comm принимает только файлы, следовательно, метод ввода kooky <(...) . Это передает содержимое через настоящий [временный] файл.

  • comm нуждается в сортированном вводе или не работает, и find отнюдь не гарантирует заказ. Он также должен быть уникальным. Первая операция find может найти несколько файлов для cover.* Таким образом, могут быть дубликаты записей. sort -u быстро оборвал их до одного. Вторая находка всегда будет уникальной.

  • dirname – удобный инструмент для получения файла dir без обращения к sed (и др.).

  • find и comm являются немного беспорядочными с их выходом. Окончательный 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, не сохраняя их вывод во временных файлах. Программа diff считает, что она работает с двумя файлами, но на самом деле это чтение из двух труб.

Команда, которая производит ввод правой руки для diff , printf "%s\n" */* , просто перечисляет каталоги альбомов. Левая команда выполняет *.cover пути *.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 Bash set -o nullglob .