Как найти только каталоги без подкаталогов? [дубликат]

Один из способов сделать это - создать собственную рекурсивную ссылку для чтения .

function readlinkWithPrint() {
    link=`readlink "$@"`
    [ -e "$link" ] && echo "$link"
    [ -h "$link" ] && readlinkWithPrint "$link"
}

Вот тест:

$ touch file
$ ln -s file symlink1
$ ln -s symlink1 symlink2
$ readlinkWithPrint symlink2
symlink1
file

К сожалению, эта функция довольно проста; параметры, которые вы предоставляете для frist readlink , не будут распространяться на остальные, плюс вы не можете читать несколько файлов.

7
28.01.2019, 21:55
4 ответа

Чтобы найти только те конечные каталоги, которые содержат файлы, вы можете объединить ответ на указанный вопросhttps://unix.stackexchange.com/a/203991/330217или аналогичные вопросыhttps://stackoverflow.com/a/4269862/10622916илиhttps://serverfault.com/a/530328с find's! -empty

find rootdir -type d -links 2 ! -empty

Проверка жестких ссылок с помощью -links 2должна работать для традиционных файловых систем UNIX. Условие -emptyне является частью стандарта POSIX, но должно быть доступно в большинстве систем Linux.

Согласно комментарию Kamil Maciorowski, традиционная семантика подсчета ссылок для каталогов недействительна для Btrfs. Это подтверждается в https://linux-btrfs.vger.kernel.narkive.com/oAoDX89D/btrfs-st-nlink-for-directories, где также упоминается Mac OS HFS+ как исключение из традиционного поведения. Для этих файловых систем необходим другой метод проверки листовых каталогов.

12
27.01.2020, 20:13

Вы можете использовать вложенные findи количество подкаталогов:

find. -type d \
  \( -exec sh -c 'find "$1" -mindepth 1 -maxdepth 1 -type d -print0 | grep -cz "^" >/dev/null 2>&1' _ {} \; -o -print \)
5
27.01.2020, 20:13

Если шаблон подстановки имени файла */расширяется до чего-то, что не является именем каталога, то текущий каталог не имеет (не -скрытых )подкаталогов.

Сfind:

find root -type d -exec sh -c 'set -- "$1"/*/; [ ! -d "$1" ]' sh {} \; ! -empty -print

Обратите внимание, что при этом символическая ссылка на каталог в конечном каталоге будет рассматриваться как каталог, поскольку шаблон будет проходить по символической ссылке.

Предикат -emptyне является стандартным, но часто используется. Без него вы бы сделали что-то похожее на обнаружение подкаталогов:

find root -type d \
    -exec sh -c 'set -- "$1"/*/; [ ! -d "$1" ]' sh {} \; \
    -exec sh -c 'set -- "$1"/*;  [   -e "$1" ]' sh {} \; -print

Или, более эффективно,

find root -type d -exec sh -c '
    dir=$1
    set -- "$dir"/*/
    [ -d "$1" ] && exit 1
    set -- "$dir"/*
    [ -e "$1" ]' sh {} \; -print

Или, используя предикат -links, о котором я забыл,(спасибо Бодо):

find root -type d \
    -links 2 \
    -exec sh -c 'set -- "$1"/*; [ -e "$1" ]' sh {} \; -print
4
27.01.2020, 20:13

Сzsh:

leafdirs=(**/*(ND/Fl2))

Задает массив $leafdirsсо списком соответствующих конечных каталогов.

Вы можете распечатать его по одному в строке с помощью:

printf '%s\n' $leafdirs

Или перебрать их с помощью:

for dir ($leafdirs) something with $dir

Это более или менее перевод ответа @Bodo GNU find, так что он работает только на традиционных Unix -, таких как файловые системы, такие как ext4, которые реализуют .и ... ] как фактические записи каталога.

  • **/:любой уровень подкаталогов
  • (NF/Fl2):квалификатор глоба
  • N:включить nullglobдля этого одного шара :не сбой, если нет совпадения. Вместо этого получите пустой список
  • D:включить dotglobдля этого одного шара :просматривать скрытые каталоги и не пропускать скрытые файлы
  • /:выбирать файлы только каталога типа (например-type d)
  • F:выберите полные каталоги :каталоги, содержащие хотя бы одну запись, отличную от .и..(подобно GNU find's! -empty)
  • l2:только каталоги с количеством ссылок 2 (например-links 2). Один для записи каталога в его родительском каталоге и один для .в нем. Любой подкаталог добавит единицу к счетчику ссылок из-за записи ..в них.
4
27.01.2020, 20:13

Теги

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