знайти всі кінцеві підкаталоги на дереві


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штати:

Ви також можете шукати файли, які мають певну кількість посилань, з '-посиланнями'. Каталоги зазвичай мають принаймні два жорстких посилання; їх. запис - другий. Якщо вони мають підкаталоги, кожен з них також має жорстке посилання, яке називається .. на його батьківський каталог. The. і .. записи в каталозі зазвичай не шукаються, якщо вони не вказані в командному рядку 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
  • Хтось може запропонувати краще рішення (не використовуючи труби та сед, це було чудово ...)
  • Чи буде працювати в будь-якій файловій системі?

3
Ви не знайдете більш ефективної, ніж -links 2хитрість. Це не буде працювати btrfs.
Стефан Шазелас

Відповіді:


3

Як додаток до вашого власного рішення з -links, я хочу лише додати, що воно не працюватиме у файлових системах, які не дотримуються конвенції про посилання Unix-каталогів. З man findпо вибору -noleafце по крайней мере , CD-ROM, MS-DOS файлова система і обсяг AFS точки монтування.

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


3

Є трохи більш очевидний варіант -empty:

find . -type d -empty

upd. Гаразд, ти маєш рацію, такий спосіб не працюватиме з файлами в dirs.

Отож, це непоправна версія з фіксованою файловою системою:

find dtest/ -type d -exec sh -c "if [ \$(find {} -maxdepth 1 -type d | wc -l) -eq 1 ]; then echo {} ; fi" \;

2
Якщо я розумію питання, кінцеві каталоги можуть містити файли. Це не буде надрукувати ці каталоги, оскільки вони не будуть "порожніми" ...
Стефан

@rush, підкаталоги можуть бути порожніми чи ні
Oz123

@ Oz123, будь ласка, перевір моє оновлення, воно повинно бути досить швидким, але трохи повільніше порівняно зі своїм способом.
пік

@rush, дякую, але мені дуже потрібно уникати труб, вони можуть зробити все повільніше.
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/{}' ';'

Це аналогічний підхід до рішення , що дозволяє поспішати , але без труб.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.