find: Sucht nach Dateien, die vorgegebenen Kriterien entsprechen

find ist eines der althergebrachten UNIX®-Werkzeuge. Seine Aufgabe ist es, rekursiv ein oder mehrere Verzeichnisse nach Dateien zu durchsuchen, die ein gegebenes Muster aufweisen. Einerseits ist das Werkzeug sehr hilfreich, andererseits ist seine Syntax nicht einfach und es braucht einige Übung bevor man es richtig anwenden kann. Die allgemeine Syntax lautet:

find [Verzeichnis] [Option(en)] [Test] [Aktion]

Ohne Angabe eines Verzeichnisses wird das aktuelle Verzeichnis durchsucht. Ohne spezielle Suchkriterien wird das Ergebnis wie „vorhanden“ gewertet und daher alle vorhandenen Dateien aufgelistet. Die möglichen Optionen, Tests und Aktionen sind derart zahlreich, dass wir hier nur einige wenige behandeln. Lassen Sie uns mit den Optionen beginnen:

Ein Test kann einer oder mehrere elementare Eigenschaften umfassen. Einige dieser Eigenschaften sind:

Es gibt zahlreiche andere Tests, die Sie in find(1) finden können. Zusammengesetzte Tests können Sie in dieser Art anwenden:

Schließlich können Sie für jede gefundene Datei auch eine Aktion festlegen. Die meist genutzten Aktionen sind:

Am besten kann man all diese Optionen und Parameter mit einigen Beispielen darstellen. Nehmen wir an, Sie wollen alle Unterverzeichnisse im Verzeichnis /usr/share auflisten. Die Eingabe dazu lautet:

# find /usr/share -type d

Angenommen, Sie betreiben einen HTTP Server und alle Ihre HTML-Dateien liegen im Verzeichnis /var/www/html, das auch das aktuelle Verzeichnis ist. Jetzt wollen Sie alle Dateien finden, die seit einem Monat nicht verändert wurden. Da die Seiten von verschiedenen Autoren stammen gibt es sowohl Dateien mit der Endung html als auch solche mit der Endung htm. Sie wollen all diese Dateien in das Verzeichnis /var/www/obsolete verlinken. Dazu geben Sie ein[17]:

# find \( -name "*.htm" -o -name "*.html" \) -a -ctime -30 -exec ln {} /var/www/obsolete \;

Dies ist ein recht komplexes Beispiel, das wir jetzt genauer erklären werden. Die Tests lauten wie Folgt:

\( -name "*.htm" -o -name "*.html" \) -a -ctime -30

wodurch das erreicht wird, was wir wollen: es findet alle Dateien, die auf .htm oder .html enden („\( -name "*.htm" -o -name "*.html" \) “) und (-a) die innerhalb der letzten 30 Tage nicht verändert wurden (-ctime -30). Beachten Sie die Klammern: sie müssen hier angewendet werden, da -a eine höhere Priorität hat. Ohne Klammern würden alle Dateien aufgelistet, die mit .htm enden und dazu alle Dateien, die mit .html enden und in den letzten 30 Tagen nicht geändert wurden. Das ist aber nicht genau das, was wir wollten. Beachten Sie auch, dass die Klammern maskiert wurden: Wenn wir ( .. ) anstelle von \( .. \) schreiben würden, hätte die shell die Klammern interpretiert und versucht, den Befehl -name "*.htm" -o -name "*.html" in einer Sub-Shell auszuführen... Weitere mögliche Arten der Maskierung bestehen in der Einfassung mit Anführungszeichen, jedoch ist hier ein Backslash vorzuziehen, da nur ein einzelnes Zeichen maskiert werden muss.

Schließlich fehlt noch der für jede Datei auszuführende Befehl:

-exec ln {} /var/www/obsolete \;

Hier muss das Zeichen ; vor der shell maskiert werden, da die Shell das Zeichen anderenfalls als Befehlstrenner interpretieren und find das Fehlen eines Argumentes für -exec melden würde.

Ein letztes Beispiel: Sie haben ein ausgedehntes Verzeichnis (/shared/images) mit allen möglichen Arten von Bilddateien. Sie benutzen regelmäßig den Befehl touch um den Zeitstempel der Datei stamp in diesem Verzeichnis als Zeitreferenz zu aktualisieren. Sie wollen nun alle JPEG-Bilder finden, die neuer als die Datei stamp sind. Da Ihre Bilder aus verschiedenen Quellen stammen, besitzen diese Bilder die Endungen jpg, jpeg, JPG oder JPEG. Natürlich wollen Sie auch keine Suche im alten Verzeichnis durchführen. Die Dateiliste soll per Mail an Sie geschickt werden (Ihr Kennzeichen ist birgit):

# find /shared/images -cnewer     \
     /shared/images/stamp       \
     -a -iregex ".*\.jpe?g"     \
     -a -not -regex ".*/old/.*" \
       | mail birgit -s "New images"

Natürlich ist es nicht gerade effizient, diese Befehlszeile jedes Mal neu eingeben zu müssen. Außerdem soll der Befehl regelmäßig ausgeführt werden. Hier ist eine einfache Lösung zur regelmäßigen Ausführung des Befehls:



[17] Beachten Sie, dass sowohl /var/www als auch /var/www/obsolete im gleichen Dateisystem liegen müssen!