znajdź wszystkie końcowe podkatalogi w drzewie


11

biorąc pod uwagę następującą strukturę:

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

16 directories, 0 files

Jak znaleźć wszystkie węzły końcowe?

Znalazłem następujące rozwiązania, które wydają się dobre, ale muszę udowodnić, że nie ma przypadku testowego, który by go zawiódł.

Strona pomocy -linksstanów:

Możesz także wyszukiwać pliki, które mają określoną liczbę linków, za pomocą „-links”. Katalogi zwykle mają co najmniej dwa twarde linki; ich . wejście jest drugie. Jeśli mają podkatalogi, każdy z nich ma również stałe łącze o nazwie .. do swojego katalogu nadrzędnego. The. i .. pozycje katalogu zwykle nie są przeszukiwane, chyba że są wymienione w wierszu polecenia find.

możliwe rozwiązanie:

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
  • Czy ktoś może zapewnić lepsze rozwiązanie (bez użycia rur i sed, to musi być wydajne ...)
  • Czy będzie działać na dowolnym systemie plików?

3
Nie znajdziesz bardziej wydajnego niż -links 2sztuczka. To nie zadziała btrfs.
Stéphane Chazelas,

Odpowiedzi:


3

Jako dodatek do twojego własnego rozwiązania -links, chcę tylko dodać, że nie będzie działać na systemach plików, które nie są zgodne z konwencją uniksowego łącza do katalogu. Z tej man findopcji -noleafsą to przynajmniej CD-ROM, systemy plików MS-DOS i punkty montowania woluminów AFS.

Dla porównania, to pytanie zostało już omówione z różnymi rozwiązaniami, które są rzeczywiście wolniejsze i zwykle uciekają się do potokowania do sed / awk i podobnych.


3

Istnieje nieco bardziej oczywista opcja -empty:

find . -type d -empty

aktualiz. Ok, masz rację, w ten sposób nie będzie działać z plikami w katalogach.

Oto wersja niezmiennego systemu plików:

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

2
Jeśli rozumiem pytanie, katalogi końcowe mogą zawierać pliki. Nie wydrukowałoby to tych katalogów, ponieważ nie byłyby „puste” ...
Stefan,

@ pośpiech, podkatalogi mogą być puste lub nie
Oz123

@ Oz123 sprawdź moją aktualizację, powinna być wystarczająco szybka, ale nieco wolniejsza w porównaniu do twojej drogi.
pędzi

@ pospiesz się, dzięki, ale naprawdę muszę unikać rur, mogą spowolnić.
Oz123

1

find . -type d -links 2działa na większości systemów plików, ale nie na wszystkich. Nie sądzę, że istnieje inny sposób, niż wiedzieć, które typy systemów plików mają właściwość polegającą na tym, że katalogi zawierają odsyłacze do siebie. GNU find wykrywa to dynamicznie (jeśli wypisuje coś o „Automatycznym włączaniu opcji find -noleaf”, wiesz, że twój system plików nie ma tej właściwości). Najpopularniejsze typy systemów plików są w porządku, ale nie FAT i btrfs.

Jeśli chcesz się upewnić, będziesz musiał przetestować każdy katalog. Jednym ze sposobów na to jest findponowne wywołanie dla każdego podkatalogu.

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

(z GNU find, można zastąpić -prunez -print -quitaby uczynić go nieco bardziej wydajne).

Innym sposobem jest przetworzenie wyniku find. Za find -depthpomocą katalogu typu liść nie znajduje się sam podkatalog.

find . -depth -type d -print0 |
awk -v RS='\0' '
    substr(previous, 1, length($0) + 1) != $0 "/"
    { previous = $0 }
'

0

Wypróbuj następujące rozwiązanie (powinno być kompatybilne z Linux, Unix i OS X):

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

Jest to podobne podejście do rozwiązania szczytu , ale bez żadnych rur.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.