Finden Sie alle End-Unterverzeichnisse in einem Baum

11

gegeben die folgende Struktur:

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

16 directories, 0 files

Wie finde ich alle Endknoten?

Ich habe die folgenden Lösungen gefunden, die gut zu sein scheinen , aber ich muss beweisen, dass es keinen Testfall gibt, der fehlschlägt.

Die Hilfeseite der -linksStaaten:

Sie können auch mit '-links' nach Dateien suchen, die eine bestimmte Anzahl von Links haben. Verzeichnisse haben normalerweise mindestens zwei feste Verbindungen. ihr . Eintrag ist der zweite. Wenn sie Unterverzeichnisse haben, hat jedes von diesen auch einen festen Link namens .. zu seinem übergeordneten Verzeichnis. Das . und .. Verzeichniseinträge werden normalerweise nicht durchsucht, es sei denn, sie werden in der Befehlszeile find angegeben.

mögliche Lösung:

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
  • Kann jemand eine bessere Lösung anbieten (ohne Verwendung von Rohren und Sed, dies ist performant ...)
  • Funktioniert es auf jedem Dateisystem?
Oz123
quelle
3
Sie werden nicht performanter als den -links 2Trick finden. Es wird nicht funktionieren btrfs.
Stéphane Chazelas

Antworten:

3

Als Ergänzung zu Ihrer eigenen Lösung mit -linksmöchte ich nur hinzufügen, dass es auf Dateisystemen, die nicht der Unix-Verzeichnisverknüpfungskonvention entsprechen, nicht funktioniert. Ab dieser man findOption -noleafsind dies mindestens CD-ROM, MS-DOS-Dateisysteme und AFS-Volume-Mount-Punkte.

Als Referenz wurde diese Frage bereits mit verschiedenen Lösungen diskutiert, die in der Tat langsamer sind und normalerweise auf Rohrleitungen zu sed / awk und ähnlichem zurückgreifen.

Miroslav Koškár
quelle
3

Es gibt eine etwas offensichtlichere Option -empty:

find . -type d -empty

upd. Ok, Sie haben Recht, auf diese Weise funktioniert es nicht mit Dateien in Verzeichnissen.

Hier handelt es sich also um eine nicht verlässliche Version eines festen Dateisystems:

find dtest/ -type d -exec sh -c "if [ \$(find {} -maxdepth 1 -type d | wc -l) -eq 1 ]; then echo {} ; fi" \;
eilen
quelle
2
Wenn ich die Frage verstehe, können Endverzeichnisse Dateien enthalten. Dies würde diese Verzeichnisse nicht drucken, da sie nicht "leer" wären ...
Stefan
@ Rush, Subdirs können leer sein oder nicht
Oz123
@ Oz123 bitte überprüfe mein Update, es sollte schnell genug sein, aber etwas langsamer im Vergleich zu deinem Weg.
Eile
@rush, danke, aber ich muss die Rohre wirklich meiden, sie können die Dinge langsamer machen.
Oz123
1

find . -type d -links 2funktioniert auf den meisten Dateisystemen, aber nicht auf allen. Ich glaube, es gibt keine andere Möglichkeit zu wissen, als zu wissen, welche Dateisystemtypen die Eigenschaft haben, dass Verzeichnisse einen Link zu sich selbst enthalten. GNU find erkennt dies dynamisch (wenn etwas über "Automatisch die Option -noleaf von find aktivieren" ausgegeben wird, wissen Sie, dass Ihr Dateisystem diese Eigenschaft nicht hat). Die meisten gängigen Dateisystemtypen sind in Ordnung, jedoch nicht FAT oder btrfs.

Wenn Sie sicher sein möchten, müssen Sie jedes Verzeichnis testen. Eine Möglichkeit, dies zu tun, besteht darin, findfür jedes Unterverzeichnis erneut aufzurufen .

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

(mit GNU find, können Sie ersetzen -prunemit -print -quit, um es ein bisschen effizienter).

Eine andere Möglichkeit besteht darin, die Ausgabe von nachzubearbeiten find. Mit find -depthist ein Blattverzeichnis eines, das keinem Unterverzeichnis von sich selbst folgt.

find . -depth -type d -print0 |
awk -v RS='\0' '
    substr(previous, 1, length($0) + 1) != $0 "/"
    { previous = $0 }
'
Gilles 'SO - hör auf böse zu sein'
quelle
0

Probieren Sie die folgende Lösung aus (sollte Linux-, Unix- und OS X-kompatibel sein):

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

Es ist ein ähnlicher Ansatz wie bei einer Eillösung , jedoch ohne Rohre.

Kenorb
quelle