Используйте GNU find, чтобы показывать только каталоги листьев

Я пытаюсь использовать GNU find для поиска только каталогов, которые не содержат других каталогов, но могут содержать или не содержать обычные файлы.

Моя лучшая догадка была до сих пор:

find dir -type d \( -not -exec ls -dA ';' \)

но это просто дает мне длинный список "."

Спасибо!

Ответ 1

Вы можете использовать ссылки, если ваша файловая система совместима с POSIX (т.е. в каталоге есть ссылка для каждого подкаталога в ней, ссылка от ее родителя и ссылка на "я" ), поэтому счетчик ссылок 2, если у него нет подкаталогов).

Следующая команда должна делать то, что вы хотите:

find dir -type d -links 2

Однако он не работает в Mac OS X (как упоминал @Piotr). Вот еще одна версия, которая работает медленнее, но работает на Mac OS X. Она основана на его версии с исправлением для обработки пробелов в именах каталогов:

find . -type d -exec sh -c '(ls -p "{}"|grep />/dev/null)||echo "{}"' \;

Ответ 2

Решение @Sylvian не работало для меня на mac os x по какой-то неясной причине. Поэтому я придумал немного более прямое решение. Надеюсь, это поможет кому-то:

find . -type d  -print0 | xargs -0 -IXXX sh -c '(ls -p XXX | grep / >/dev/null) || echo XXX' ;

Пояснение:

  • ls -p завершает каталоги с помощью '/'
  • поэтому (ls -p XXX | grep / >/dev/null) возвращает 0, если нет каталогов
  • -print0 && & -0 означает, что xargs обрабатывает пробелы в именах каталогов

Ответ 3

Как насчет этого? Он переносится, и он не зависит от финишных ссылок. Обратите внимание, однако, что важно поставить root/folder без конечного /.

find root/folder -type d | awk '{ if (length($0)<length(prev) || substr($0,1,length(prev))!=prev) print prev; prev=($0 "/") } END { print prev }'

Ответ 4

Вот решение, которое работает на Linux и OS X:

find . -type d -execdir bash -c '[ "$(find {} -mindepth 1 -type d)" ] || echo $PWD/{}' \; 

или

find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' \;