6

Как я могу найти все подкаталоги в каталоге (только на 1 уровень ниже), которые не содержат данный файл?

2 ответа2

5

Есть несколько способов сделать это с помощью 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 исключает последний вид.

1

Прямо в сценарии оболочки:

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

перед командой.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .