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

Попробуйте выполнить команды: free, top или cat /proc/meminfo

С помощью top вы можете нажать shift + m для сортировки процессов с использованием (резидентной) памяти.

1
задан 10 October 2012 в 14:39

2 ответа

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

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

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

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

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

Вы не уверены в этом случае, а расширение может быть 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 "{}", только имена файлов каталога find в настоящее время перемещаются egrep (вместо grep) используют расширенные регулярные выражения ; -i делает регистр поиска нечувствительным, -q заставляет его опускать любой выход "^cover\.(jpg|png)$" - это шаблон поиска. В этом примере оно соответствует, например, cOver.png, Cover.JPG или cover.png. [F20] должен быть экранирован, иначе это означает, что он соответствует любому символу. ^ обозначает начало строки, $ его конец

Другие примеры шаблонов поиска для egrep:

Подставьте часть egrep -i -q "^cover\.(jpg|png)$":

] Для каждой директории необходимо создать оболочку sh, поскольку при использовании find egrep -q "^cover\.(jpg|png)$" невозможно выполнить трубку: совпадения cover.png, cover.jpg, но NOT Cover.jpg ( чувствительность к регистру не отключена). ls -1 "{}" выводит только имена файлов каталога find в настоящее время перемещаются

Для получения дополнительной информации об этом, проверьте Регулярные выражения.

63
ответ дан 25 May 2018 в 05:48
  • 1
    Абсолютно красивая - с проблемой, что небезопасно выбирать между случаями или разными расширениями (я пробовал подстановочный знак, но не пошел). Интересно, есть ли лучшая альтернатива test. – Oli♦ 6 October 2012 в 05:08
  • 2
    Хм, вы можете вложить эту находку с этим -exec bash -c '[[ -n $(find "{}" -iname "cover.*") ]]' \;, но это довольно грязно с точки зрения оптимизации. Это действительно работает. – Oli♦ 7 October 2012 в 03:26
  • 3
    Я обнаружил, что вы можете передать test нагрузку -o EXPRESSION для OR запросов ... например: test -e "{}/cover.jpg" -o -e "{}/cover.png", которая лучше, чем выполнение полномасштабного поиска, но она все еще чувствительна к регистру. – Oli♦ 9 October 2012 в 13:10
  • 4
    Я должен отметить, что сравнение производительности этого (два теста, за мой последний комментарий) против двух других решений (comm'd find и comm'd globbing), это, безусловно, самый медленный (684ms против 40 мс и 50 мс соответственно) – Oli♦ 16 May 2013 в 18:43
  • 5
    Исходное решение в ответ занимает второе место и ломается при обстоятельствах, которые имеют $ в имени dir (например, Ke $ ha). – Oli♦ 16 May 2013 в 18:45

Это гораздо приятнее решить с помощью 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 и печатает имена своих каталогов.

Тестирование:

$ 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/b и foo/bar не имеют cover.jpg.

Есть некоторые разбитые угловые случаи , как это по умолчанию * расширяется до самого себя, если оно ничего не соответствует. Это можно решить с помощью Bash set -o nullglob.

7
ответ дан 25 May 2018 в 05:48
  • 1
    Извинения за поздний ответ. Это интересная идея, но: обложки могут быть в png и jpg и не будет comm чище, чем diff? – Oli♦ 16 May 2013 в 18:27
  • 2
    comm -3 <(printf "%s\n" */*/cover* | sed -r 's/\/[^\/]+$//' | sort -u) <(printf "%s\n" */*) кажется разумным компромиссом без пуха diff. Это, однако, немного медленнее, чем моя двойная находка. – Oli♦ 16 May 2013 в 18:43

Другие вопросы по тегам:

Похожие вопросы: