Показать все папки, в которых нет подкаталога [дубликат]

Как мне отобразить все папки, у которых нет подкаталогов, с помощью терминала?

3
задан 13 June 2016 в 21:24

2 ответа

Попробуйте это:

find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a)print d}' RS='\0'

Как это работает

Для сейфа для всех возможных имен каталогов мы используем nul-разделенные списки для каждого шага конвейера.

  • find . -type d -print0

    Это получает список всех подкаталогов текущего каталога.

  • sort -z

    Это сортирует каталоги который как эффект помещения подкаталогов после их родительских каталогов.

  • gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a)print d}' RS='\0'

    Это помещает список каталогов в ассоциативном массиве. Для каждого добавленного каталога это проверяет, чтобы видеть, находится ли родитель каталогов в массиве. Если это, это удаляет его из массива. Давайте посмотрим на этот шаг за один раз:

    • a[$0]

      Это добавляет каталог, названный в текущей записи как ключ в массиве a. (Мы не присваиваем значение ему, потому что нам не нужно значение.)

    • sub(/[/][^/]*$/, "")

      Это удаляет последний подкаталог из $0 так, чтобы $0 теперь обращается к родительскому каталогу.

    • if ($0 in a) delete a[$0]

      Если родительский каталог является ключом a, затем мы удаляем его.

    • END{for (d in a) print d}

      Это распечатывает каждый каталог, для которого мы не нашли подкаталогов. (Из-за пути работают массивы awk, вывод без определенного порядка.)

    • RS='\0'

      Это говорит awk ожидать nul-разделенный вход. Другими словами, на входе, awk использует nul символ в качестве разделителя записей.

Пример

Давайте создадим некоторые каталоги и затем проверим, что вывод перечисляет только те каталоги, которые не имеют никаких подкаталогов:

$ mkdir -p a/b/c/x1 a/b/c/x2 a/b/x3 a/x4
$ find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a)print d}' RS='\0'
./a/x4
./a/b/x3
./a/b/c/x1
./a/b/c/x2

Изменение: печать только базового имени каталога

find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a) {sub(/^.*[/]/,"",d); print d}}' RS='\0'

Для иллюстрирования давайте выполним это против тех же каталогов как выше:

$ find . -type d -print0 | sort -z | gawk '{a[$0]; sub(/[/][^/]*$/, ""); if ($0 in a) delete a[$0]} END{for (d in a) {sub(/^.*[/]/,"",d); print d}}' RS='\0'
x5
x4
x3
x1
x2
2
ответ дан 13 June 2016 в 21:24

Вы могли сделать find-within-a-find, например,

find . -type d -exec bash -c '
  [[ -z $(find "$1" -mindepth 1 -type d -print -quit) ]] && printf "%s\n" "$1"      
' bash {} \;

, Если Вы не хотите ведущие компоненты контура, затем

find . -type d -exec bash -c '
  [[ -z $(find "$1" -mindepth 1 -type d -print -quit) ]] && printf "%s\n" "${1##*/}"
' bash {} \;
<час>

, я не могу сдержать чувство, что должен быть "умный" способ сделать это с помощью -depth

2
ответ дан 13 June 2016 в 21:24

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

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