Login
Login-Name Passwort


 
Newsletter
Werbung

Mo, 1. Januar 2001, 00:00

Shell-Workshop, Teil 4

Wer suchet, der findet...

Das Suchen nach Dateien ist keine außergewöhnlich seltene Aufgabe, weshalb es schon seit langer Zeit grafische Programme gibt, die das Suchen anhand diverser benutzerdefinierter Kriterien erlauben. Das Programm "find" bietet gegenüber grafischen Such-Dialogen zwei Vorteile: Es ist es nicht nur sehr flexibel, was die Suchkriterien angeht, sondern kann auch direkt auf alle entsprechenden Dateien eine Aktion anwenden.

Die allgemeine Syntax von "find" lautet:

find verzeichnisse suchkriterien

Dabei ist "verzeichnisse" eine Liste von Verzeichnissen, unterhalb von denen gesucht werden soll und die Suchkriterien bestimmen die Eigenschaften, die eine Datei (oder ein Verzeichnis, oder ein Link usw.) aufweisen muss, damit dessen Name ausgegeben wird.

Die wohl häufigste Anwendung ist, dass man den Namen einer Datei - oder zumindest einen Teil ihres Namens - kennt und nach ihr suchen möchte. Dazu gibt es die Option -name. Der Parameter, der auf diese Option folgt, gibt das Muster an, auf das der Dateiname passen muss, d.h. man kann hier mit den Metazeichen ("?", "*", Zeichenklassen, ...) arbeiten. Natürlich muss man das Muster dabei in Hochkommata setzen, weil die Bash es sonst entsprechend den Dateinamen im aktuellen Verzeichnis expandieren würde, was hier ja gerade nicht gewünscht ist. Um vom Wurzelverzeichnis (/) ausgehend nach Dateien zu suchen, deren Name mit einem großen X beginnt (die meisten - wenn nicht alle - davon werden wohl etwas mit X11 zu tun haben), kann man also folgendes Kommando verwenden:

find / -name 'X*'

Ein weiteres interessantes Kriterium ist (wieder mal), ob es sich um eine normale Datei oder eben um ein Verzeichnis handelt, wofür es die Option -type gibt. Als nächstes Argument muss man angeben, was für ein Typ es sein soll, wobei auch hier "d" für Verzeichnisse und "f" für normale Dateien steht. Alle Verzeichnisse unterhalb des aktuellen Verzeichnisses kann man also so auflisten lassen (wenn keine Verzeichnisse angegeben werden, wird vom aktuellen Verzeichnis ausgehend gesucht):

find -type d

Das kann durchaus einen sehr großen Nuzten haben. Beispielsweise dann, wenn man die Rechte aller Verzeichnisse rekursiv (also auch die aller Unterverzeichnisse) ändern möchte, aber die Dateien darin unangetastet bleiben sollen und genau das ist etwas, wonach regelmäßig in GNU/Linux-Foren gefragt wird. Eine Möglichkeit, das zu realisieren wäre, die Ausgabe von "find" mit Hilfe einer Pipes in die Eingabe von "xargs" zu leiten. "xargs" liest Zeilen (in der Praxis sind dies dann meist Dateinamen, wie sie von "find" ausgegeben werden) aus seiner Eingabe und führt für jede genannte Zeile einen Befehl aus (der über Kommandozeilenargumente an "xargs" übergegeben wird), wobei die jeweilige Zeile als Parameter an das Kommando angehängt wird. Das lässt sich hervorragend in Kombination mit find verwenden; der folgende Befehl demonstriert die Funktionsweise von xargs:

find -type d | xargs chmod +r

Hier werden alle Verzeichnisse durch die Pipe (|) an "xargs" geleitet. Für jedes Verzeichnis würde xargs hier "chmod +r verzeichnisname" ausführen, wodurch alleen Benutzern erlaubt wird, anzeigen zu lassen, was sich in den Verzeichnissen befindet.

Solche Aufgaben kann man aber nicht nur mit "xargs" lösen; es gibt eine weitere Möglichkeit, die von "find" selbst angeboten wird und sogar noch flexibler ist. Man kann nämlich angeben, was "find" mit passenden Dateien, Verzeichnissen etc. machen soll. Das Standardverhalten ist -print, also das reine Ausgeben des Namens. Eine andere Möglichkeit ist -exec. Nach -exec folgt ein beliebiges Kommando, wobei die Zeichenfolge "{}" eine Sonderbedeutung hat: Sie wird durch den jeweiligen Dateinamen ersetzt. Das bedeutet, dass der Name mehrfach und an beliebigen Positionen vorkommen kann. Man muss "find" allerdings noch mitteilen, welche Argumente zu dem Kommando gehören und welche dann wieder von "find" selbst verarbeitet werden sollen. Dies wird durch das Semikolon realisiert, wobei man ihm einen Backslash voranstellen muss, damit es nicht direkt von der Bash als Trennzeichen von mehreren Kommandos betrachtet wird. Das obige Beispiel würde mit "find" alleine daher so aussehen:

find -type d -exec chmod +r {} \;

Wenn es einem zu riskant ist, ein Kommando auf alle Dateien anzuwenden, weil man befürchtet, dass doch mehr Dateien als ursprünglich erwartet dem angegebenen Kriterium entsprechen könnten, kann man natürlich zuerst die Ergebnisse der Suche ausgeben lassen und schauen, ob man mit dem Ergebis zufrieden ist, um danach das gleiche Kommando nochmal abarbeiten zu lassen, aber diesmal mit dem -exec-Teil. Eine andere Möglichkeit wäre die Verwendung von -ok. Dieser Parameter wird ganz genauso verwendet wie -exec, aber vor dem Ausführen jeder Anweisung fragt er den Benutzer, ob es ausgeführt werden soll. Um beispielsweise alle Coredumps, die im System herumliegen, aufzuspühren und evtl. gleich zu entfernen, kann man folgendes Kommando verwenden:

find / -name core -ok rm {} \;

Subshells

Für Kommandos, die keine Eingaben verlangen und keine Ausgabe generieren, aber längere Zeit brauchen (wie es eben bei "find" mit -exec-Option häufig der Fall ist), ist es oft sinnvoll, das Kommando im Hintergrund ausführen zu lassen, damit man das jeweilige Terminal derweil weiterbenutzen kann. Wenn ein im Hintergrund gestarteter Prozess beendet ist, dann informiert die Bash einem außerdem darüber, d.h. man kann sich problemlos vorübergehend anderen Aufgaben widmen, bis eine Aufgabe im Hintergrund abgearbeitet wurde. Es ist keinesfalls kompliziert, ein Kommando in den Hintergrund zu schicken: Man muss dazu lediglich ein Kaufsmanns-Und ("&", auch Ampersand genannt) an das Ende setzen:

updatedb &

Das Kommando "updatedb" generiert übrigens die Datenbank, die von "locate" verwendet wird, um schnell und einfach nach Dateien anhand des Namens suchen zu können. Näheres wie immer in den Manual-Pages.

Besonders interessant dürfte das Starten von Programmen im Hintergrund allerdings sein, wenn man dabei mehrere Kommandos zusammenfassen kann. Das Zusammenfassen wird realisiert, indem man um mehrere Kommandos ein Klammernpaar macht. Diese werden dann in einer Subshell (also einem eigenen Bash-Prozess) gestartet. Das hat den großen Vorteil, dass man die Ausgabe mehrerer Kommandos in eine gemeinsame Pipe lenken kann (also in die Eingabe eines Prozesses) oder eben in eine Datei, wobei letzteres wie folgt funktioniert:

(uptime; uname -a; df) >/tmp/status

Hier wird die Ausgabe einiger System-Statuskommandos hintereinander in die Datei /tmp/status geschrieben. Wie gewohnt kann man auch eine Subshell in den Hintergrund schicken:

(find -name 'mini-*.jpg' | xargs rm) &

In diesem Beispiel würden alle Vorschau-Versionen von Jpeg-Bildern gelöscht (vorausgesetzt, diese wurden konsequent so benannt, dass ihr Name mit "mini-" beginnt).

Kommentare (Insgesamt: 0 || Kommentieren )
Pro-Linux
Pro-Linux @Facebook
Neue Nachrichten
Werbung