So durchlaufen Sie einen Verzeichnisbaum unter Linux
Veröffentlicht: 2022-07-21
Mit Verzeichnissen unter Linux können Sie Dateien in verschiedenen, separaten Sammlungen gruppieren. Der Nachteil ist, dass es mühsam wird, von Verzeichnis zu Verzeichnis zu wechseln, um eine sich wiederholende Aufgabe auszuführen. So automatisieren Sie das.
Alles über Verzeichnisse
Der erste Befehl, den Sie lernen, wenn Sie in Linux eingeführt werden, ist wahrscheinlich ls
, aber cd
wird nicht weit dahinter liegen. Verzeichnisse zu verstehen und sich darin zu bewegen, insbesondere verschachtelte Unterverzeichnisse, ist ein grundlegender Teil des Verständnisses, wie Linux sich selbst organisiert und wie Sie Ihre eigene Arbeit in Dateien, Verzeichnisse und Unterverzeichnisse organisieren können.
Das Konzept eines Verzeichnisbaums zu verstehen – und wie man sich zwischen ihnen bewegt – ist einer der vielen kleinen Meilensteine, die Sie passieren, wenn Sie sich mit der Landschaft von Linux vertraut machen. Wenn Sie cd
mit einem Pfad verwenden, gelangen Sie zu diesem Verzeichnis. Shortcuts wie cd ~
oder cd
allein bringen Sie zurück in Ihr Home-Verzeichnis, und cd ..
bringt Sie im Verzeichnisbaum eine Ebene nach oben. Einfach.
Es gibt jedoch keine ebenso einfache Möglichkeit, einen Befehl in allen Verzeichnissen eines Verzeichnisbaums auszuführen. Es gibt verschiedene Möglichkeiten, wie wir diese Funktionalität erreichen können, aber es gibt keinen Standard-Linux-Befehl, der diesem Zweck gewidmet ist.
Einige Befehle wie ls
haben Befehlszeilenoptionen, die sie dazu zwingen, rekursiv zu arbeiten, was bedeutet, dass sie in einem Verzeichnis beginnen und sich methodisch durch den gesamten Verzeichnisbaum unterhalb dieses Verzeichnisses arbeiten. Für ls
ist es die Option -R
(rekursiv).
Wenn Sie einen Befehl verwenden müssen, der keine Rekursion unterstützt, müssen Sie die rekursive Funktionalität selbst bereitstellen. Hier ist, wie das geht.
VERWANDT: 37 Wichtige Linux-Befehle, die Sie kennen sollten
Der Baumbefehl
Der tree
wird uns bei der vorliegenden Aufgabe nicht helfen, aber er macht es einfach, die Struktur eines Verzeichnisbaums zu sehen. Es zeichnet den Baum in einem Terminalfenster, sodass wir einen sofortigen Überblick über die Verzeichnisse und Unterverzeichnisse erhalten, aus denen der Verzeichnisbaum besteht, und ihre relativen Positionen im Baum.
Sie müssen tree
installieren.
Unter Ubuntu müssen Sie Folgendes eingeben:
sudo apt Baum installieren
Verwenden Sie auf Fedora:
sudo dnf Baum installieren
Auf Manjaro lautet der Befehl:
sudo pacman -Sy-Baum
Die Verwendung von tree
ohne Parameter zeichnet den Baum unterhalb des aktuellen Verzeichnisses.
Baum
Sie können einen Pfad zum tree
in der Befehlszeile übergeben.
Baumarbeit
Die Option -d
(Verzeichnisse) schließt Dateien aus und zeigt nur Verzeichnisse an.
Baum -d Arbeit
Dies ist der bequemste Weg, um sich einen klaren Überblick über die Struktur eines Verzeichnisbaums zu verschaffen. Der hier gezeigte Verzeichnisbaum wird in den folgenden Beispielen verwendet. Es gibt fünf Textdateien und acht Verzeichnisse.
Analysieren Sie die Ausgabe von ls nicht, um Verzeichnisse zu durchsuchen
Ihr erster Gedanke könnte sein, wenn ls
einen Verzeichnisbaum rekursiv durchlaufen kann, warum nicht ls
verwenden, um genau das zu tun und die Ausgabe in einige andere Befehle zu leiten, die die Verzeichnisse parsen und einige Aktionen ausführen?
Das Analysieren der Ausgabe von ls
gilt als schlechte Praxis. Aufgrund der Fähigkeit von Linux, Datei- und Verzeichnisnamen zu erstellen, die alle möglichen seltsamen Zeichen enthalten, wird es sehr schwierig, einen generischen, universell korrekten Parser zu erstellen.
Möglicherweise erstellen Sie niemals wissentlich einen so absurden Verzeichnisnamen, aber ein Fehler in einem Skript oder einer Anwendung könnte dies tun.
Das Parsen legitimer, aber schlecht durchdachter Datei- und Verzeichnisnamen ist fehleranfällig. Es gibt andere Methoden, die wir verwenden können, die sicherer und viel robuster sind, als sich auf die Interpretation der Ausgabe von ls
zu verlassen.
Verwenden des Find-Befehls
Der Befehl find
hat eingebaute rekursive Fähigkeiten und kann auch Befehle für uns ausführen. Auf diese Weise können wir leistungsstarke Einzeiler erstellen. Wenn es etwas ist, das Sie wahrscheinlich in Zukunft verwenden möchten, können Sie Ihren Einzeiler in einen Alias oder eine Shell-Funktion umwandeln.
Dieser Befehl durchläuft rekursiv den Verzeichnisbaum und sucht nach Verzeichnissen. Jedes Mal, wenn es ein Verzeichnis findet, gibt es den Namen des Verzeichnisses aus und wiederholt die Suche innerhalb dieses Verzeichnisses. Nachdem das Durchsuchen eines Verzeichnisses abgeschlossen ist, verlässt es dieses Verzeichnis und nimmt die Suche in seinem übergeordneten Verzeichnis wieder auf.
find work -type d -execdir echo "In:" {} \;
Sie können anhand der Reihenfolge, in der die Verzeichnisse aufgelistet sind, sehen, wie die Suche durch den Baum fortschreitet. Indem Sie die Ausgabe des Befehls tree
mit der Ausgabe des find
vergleichen, sehen Sie, wie find
jedes Verzeichnis und jedes Unterverzeichnis der Reihe nach durchsucht, bis es auf ein Verzeichnis ohne Unterverzeichnisse trifft. Es geht dann eine Ebene zurück und nimmt die Suche auf dieser Ebene wieder auf.
So setzt sich der Befehl zusammen.
- find : Der
find
Befehl. - work : Das Verzeichnis, in dem die Suche gestartet werden soll. Dies kann ein Pfad sein.
- -type d : Wir suchen nach Verzeichnissen.
- -execdir : Wir werden in jedem Verzeichnis, das wir finden, einen Befehl ausführen.
- echo „In:“ {} : Dies ist der Befehl. Wir geben einfach den Namen des Verzeichnisses an das Terminalfenster zurück. Das „{}“ enthält den Namen des aktuellen Verzeichnisses.
- \; : Dies ist ein Semikolon, das zum Beenden des Befehls verwendet wird. Wir müssen es mit dem Backslash maskieren, damit Bash es nicht direkt interpretiert.
Mit einer kleinen Änderung können wir den Befehl find dazu bringen, Dateien zurückzugeben, die mit einem Suchhinweis übereinstimmen. Wir müssen die Option -name und einen Suchhinweis einfügen. In diesem Beispiel suchen wir nach Textdateien, die mit „*.txt“ übereinstimmen, und geben ihren Namen an das Terminalfenster zurück.

find work -name "*.txt" -type f -execdir echo "Found:" {} \;
Ob Sie nach Dateien oder Verzeichnissen suchen, hängt davon ab, was Sie erreichen möchten. Um einen Befehl in jedem Verzeichnis auszuführen, verwenden -type d
. Um einen Befehl für jede übereinstimmende Datei auszuführen, verwenden -type f
.
Dieser Befehl zählt die Zeilen in allen Textdateien im Startverzeichnis und Unterverzeichnissen.
find work -name "*.txt" -type f -execdir wc -l {} \;
VERWANDT: So verwenden Sie den Find-Befehl unter Linux
Durchsuchen von Verzeichnisbäumen mit einem Skript
Wenn Sie Verzeichnisse innerhalb eines Skripts durchsuchen müssen, können Sie den Befehl find
in Ihrem Skript verwenden. Wenn Sie die rekursiven Suchen selbst durchführen müssen oder möchten, können Sie dies auch tun.
#!/bin/bash shopt -s dotglob nullglob Funktion rekursiv { lokales aktuelles_dir dir_or_file für aktuelles_dir in $1; tun echo "Verzeichnisbefehl für:" $aktuelles_dir für dir_or_file in "$aktuelles_dir"/*; tun if [[ -d $dir_or_file ]]; dann rekursives "$dir_or_file" anders wc $dir_or_file fi erledigt erledigt } rekursiv "$1"
Kopieren Sie den Text in einen Editor und speichern Sie ihn als „recurse.sh“, dann verwenden Sie den Befehl chmod
, um ihn ausführbar zu machen.
chmod +x recurse.sh
Das Skript setzt zwei Shell-Optionen, dotglob
und nullglob
.
Die dotglob
Einstellung bedeutet Datei- und Verzeichnisnamen, die mit einem Punkt beginnen „ .
“ wird zurückgegeben, wenn Suchbegriffe mit Platzhaltern erweitert werden. Dies bedeutet effektiv, dass wir versteckte Dateien und Verzeichnisse in unsere Suchergebnisse aufnehmen.
Die nullglob
Einstellung bedeutet, dass Suchmuster, die keine Ergebnisse finden, als leere oder Nullzeichenfolge behandelt werden. Sie verwenden nicht standardmäßig den Suchbegriff selbst. Mit anderen Worten, wenn wir mit dem Sternchen-Platzhalter „ *
“ nach allem in einem Verzeichnis suchen, aber keine Ergebnisse erhalten, erhalten wir einen Null-String anstelle eines Strings, der ein Sternchen enthält. Dadurch wird verhindert, dass das Skript versehentlich versucht, ein Verzeichnis mit dem Namen „*“ zu öffnen oder „*“ als Dateinamen zu behandeln.
Als nächstes definiert es eine Funktion namens recursive
. Hier passieren die interessanten Dinge.
Es werden zwei Variablen namens current_dir
und dir_or_file
. Dies sind lokale Variablen und können nur innerhalb der Funktion referenziert werden.
Innerhalb der Funktion wird auch eine Variable namens $1
verwendet. Dies ist der erste (und einzige) Parameter, der an die Funktion übergeben wird, wenn sie aufgerufen wird.
Das Skript verwendet zwei for
-Schleifen, von denen eine in der anderen verschachtelt ist. Die erste (äußere) for
-Schleife wird für zwei Dinge verwendet.
Eine besteht darin, den gewünschten Befehl in jedem Verzeichnis auszuführen. Alles, was wir hier tun, ist, den Namen des Verzeichnisses an das Terminalfenster zurückzugeben. Sie könnten natürlich jeden Befehl oder jede Befehlsfolge verwenden oder eine andere Skriptfunktion aufrufen.
Als Zweites überprüft die äußere for-Schleife alle Dateisystemobjekte, die sie finden kann – entweder Dateien oder Verzeichnisse. Dies ist der Zweck der inneren for
-Schleife. Jeder Datei- oder Verzeichnisname wird wiederum an die dir_or_file
Variable übergeben.
Die Variable dir_or_file
wird dann in einer if-Anweisung getestet, um zu sehen, ob es sich um ein Verzeichnis handelt.
- Ist dies der Fall, ruft sich die Funktion selbst auf und übergibt den Namen des Verzeichnisses als Parameter.
- Wenn die Variable
dir_or_file
kein Verzeichnis ist, muss es sich um eine Datei handeln. Alle Befehle, die Sie auf die Datei angewendet haben möchten, können von derelse
-Klausel derif
-Anweisung aufgerufen werden. Sie könnten auch eine andere Funktion innerhalb desselben Skripts aufrufen.
Die letzte Zeile im Skript ruft die recursive
Funktion auf und übergibt den ersten Befehlszeilenparameter $1
als Startverzeichnis für die Suche. Dies ist der Startschuss für den gesamten Prozess.
Lassen Sie uns das Skript ausführen.
./recurse.sh funktionieren
Die Verzeichnisse werden durchlaufen, und der Punkt im Skript, an dem ein Befehl in jedem Verzeichnis ausgeführt werden würde, wird durch die Zeilen „Verzeichnisbefehl für:“ angezeigt. Auf gefundenen Dateien wird der Befehl wc
ausgeführt, um Zeilen, Wörter und Zeichen zu zählen.
Das erste verarbeitete Verzeichnis ist „work“, gefolgt von jedem verschachtelten Verzeichniszweig des Baums.
Ein interessanter Punkt ist, dass Sie die Reihenfolge ändern können, in der die Verzeichnisse verarbeitet werden, indem Sie die verzeichnisspezifischen Befehle von oberhalb der inneren for-Schleife zu unterhalb verschieben.
Lassen Sie uns die Zeile „Directory command for:“ hinter das done
der inneren for
-Schleife verschieben.
#!/bin/bash shopt -s dotglob nullglob Funktion rekursiv { lokales aktuelles_dir dir_or_file für aktuelles_dir in $1; tun für dir_or_file in "$aktuelles_dir"/*; tun if [[ -d $dir_or_file ]]; dann rekursives "$dir_or_file" anders wc $dir_or_file fi erledigt echo "Verzeichnisbefehl für:" $aktuelles_dir erledigt } rekursiv "$1"
Jetzt führen wir das Skript noch einmal aus.
./recurse.sh funktionieren
Dieses Mal werden die Befehle zuerst von den tiefsten Ebenen auf die Verzeichnisse angewendet und arbeiten sich die Zweige des Baums hinauf. Das als Parameter an das Skript übergebene Verzeichnis wird zuletzt verarbeitet.
Wenn es wichtig ist, zuerst tiefere Verzeichnisse verarbeiten zu lassen, können Sie dies wie folgt tun.
Rekursion ist seltsam
Es ist, als würde man sich selbst auf seinem eigenen Telefon anrufen und eine Nachricht für sich selbst hinterlassen, um sich selbst mitzuteilen, wann man sich das nächste Mal trifft – immer wieder.
Es kann einige Anstrengungen erfordern, bevor Sie die Vorteile erkennen, aber wenn Sie dies tun, werden Sie feststellen, dass dies eine programmatisch elegante Möglichkeit ist, schwierige Probleme anzugehen.
VERWANDT: Was ist Rekursion in der Programmierung und wie wird sie verwendet?