найти все конечные подкаталоги в дереве

11

учитывая следующую структуру:

oz123@debian:~/ $ tree .
.
├── a
│   ├── a1
│   ├── a2
│   └── a3
├── a1
│   ├── a11
│   ├── a12
│   └── a31
├── b
│   └── b1
│       ├── b11
│       │   └── b21
│       │       └── b31
│       ├── b12
│       └── b3
└── c

16 directories, 0 files

Как мне найти все конечные узлы?

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

Страница помощи -linksсостояний:

Вы также можете искать файлы, которые имеют определенное количество ссылок, с помощью «-links». Каталоги обычно имеют как минимум две жесткие ссылки; их. запись вторая. Если у них есть подкаталоги, у каждого из них также есть жесткая ссылка, называемая .. на свой родительский каталог. . и .. записи каталога обычно не ищутся, если они не упомянуты в командной строке find.

возможное решение:

oz123@debian:~/ $ find .  -type d  -links 2
./a/a2
./a/a3
./a/a1
./c
./a1/a31
./a1/a11
./a1/a12
./b/b1/b12
./b/b1/b3
./b/b1/b11/b21/b31
  • Может ли кто-нибудь предложить лучшее решение (без использования каналов и SED, это будет эффективным ...)
  • Будет ли это работать на любой файловой системе?
Oz123
источник
3
Вы не найдете более производительный, чем -links 2трюк. Это не сработает btrfs.
Стефан Шазелас

Ответы:

3

В качестве дополнения к вашему собственному решению -links, я хочу просто добавить, что оно не будет работать на файловых системах, которые не следуют соглашению о связях каталогов Unix. С этого man findпараметра -noleafэто как минимум CD-ROM, файловые системы MS-DOS и точки монтирования тома AFS.

Для справки, этот вопрос уже обсуждался с различными решениями, которые действительно медленнее и обычно прибегают к конвейеру в sed / awk и тому подобное.

Мирослав Кошкар
источник
3

Есть немного более очевидный вариант -empty:

find . -type d -empty

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

Так что здесь это исправленная версия файловой системы:

find dtest/ -type d -exec sh -c "if [ \$(find {} -maxdepth 1 -type d | wc -l) -eq 1 ]; then echo {} ; fi" \;
порыв
источник
2
Если я понимаю вопрос, конечные каталоги могут содержать файлы. Это не напечатало бы эти каталоги, поскольку они не были бы "пустыми" ...
Стефан
@rush, subdirs могут быть пустыми или нет
Oz123
@ Oz123, пожалуйста, проверьте мое обновление, оно должно быть достаточно быстрым, но немного медленнее по сравнению с вашим.
Раш
@ спешу, спасибо, но мне действительно нужно избегать каналов, они могут замедлить работу.
Oz123
1

find . -type d -links 2работает на большинстве файловых систем, но не на всех. Я не думаю, что есть способ узнать, кроме как знать, какие типы файловых систем имеют свойство, что каталоги содержат ссылку на себя. GNU find обнаруживает это динамически (если он печатает что-то об «Автоматическом включении параметра find -noleaf», вы знаете, что ваша файловая система не имеет этого свойства). Наиболее распространенные типы файловых систем в порядке, но не FAT или btrfs.

Если вы хотите быть уверены, вам придется протестировать каждый каталог. Один из способов сделать это - вызвать findснова для каждого подкаталога.

find . -type d ! -exec sh -c '
   find "$1/." ! -name . -type d -prune | grep -q "^"' sh {} \; -print

(с GNU findвы можете заменить -pruneна, -print -quitчтобы сделать его немного более эффективным).

Другим способом является постобработка вывода find. При find -depthэтом конечный каталог - это каталог, который не следует за собственным подкаталогом.

find . -depth -type d -print0 |
awk -v RS='\0' '
    substr(previous, 1, length($0) + 1) != $0 "/"
    { previous = $0 }
'
Жиль "ТАК - перестань быть злым"
источник
0

Попробуйте следующее решение (должно быть совместимо с Linux, Unix и OS X):

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

Это похожий подход к быстрому решению , но без каких-либо труб.

kenorb
источник