Как я могу найти все подкаталоги в каталоге (только на 1 уровень ниже), которые не содержат данный файл?
2 ответа
Есть несколько способов сделать это с помощью find.
Подход 1 менее хакерский и будет хорошо работать со странными именами каталогов (например, имена каталогов, содержащие новые строки), но подход 2 должен быть более быстрым, если существует много каталогов.
Подход 1
команда
find DIR -type d -mindepth 1 -maxdepth 1 -not -exec test -f {}/FILENAME \; \
-print | sort
Как это устроено
find DIR -type d -mindepth 1 -maxdepth 1находит все каталоги (-type d) в DIR с глубиной 1.-not -exec test -f {}/FILENAME \;Истинно, если и только если файл с именем FILENAME не может быть найден в текущем обработанном каталоге ({}).-printвыведет нужные имена каталогов.При желании
sortотсортирует вывод по алфавиту.
Подход 2
команда
( find DIR -type f -mindepth 2 -maxdepth 2 -name FILENAME -printf "%h\n" ; \
find DIR -type d -mindepth 1 -maxdepth 1 ) | sort | uniq -u
Как это устроено
find DIR -type f -mindepth 2 -maxdepth 2 -name FILENAMEнаходит все файлы (-type f) с именем FILENAME в подкаталогах DIR (файлы каталогов глубины 1 имеют глубину 2).-print "%h\n"вывести имена каталогов, содержащих файлы с именем FILENAME, с последующим переводом строки.find DIR -type d -mindepth 1 -maxdepth 1перечислить все каталоги (-type d) в DIR с глубиной 1.sortсортирует выходные данные в алфавитном порядке (выходные данные должны быть отсортированы при передаче вuniq).uniq -uпечатает только уникальные строки.Каждый подкаталог DIR перечисляется по крайней мере один раз, но те, которые содержат файл с именем FILENAME, появляются в списке дважды.
uniq -uисключает последний вид.
Прямо в сценарии оболочки:
for i in DIRECTORY/*/; do [ -f "$i/FILENAME" ] || basename "$i"; done
for i in DIRECTORY/*/использует расширение оболочки, чтобы безопасно (не должно быть проблем со странными именами каталогов) выдавать все подкаталоги определенного каталога. Обратите внимание на косую черту, чтобы дать только каталоги.[ -f "$i/FILENAME" ]возвращает true, если файл с именемFILENAMEсуществует в каталоге на этой итерации.||Оператор запускает следующую команду, если первая вернула false, т.е. только если файл не существует в каталоге.basename "$i"печатает имя каталога (если имя файла там не найдено). Если вам нужен полный путь, а не только имя каталога, заменитеbasenameнаechoилиreadlink -fили что-то еще в предпочтении.
Если вы также хотите включить скрытые каталоги, запустите (в Bash)
shopt -s dotglob
перед командой.
