find
find (/usr/bin/find
) ist ein Programm zur Durchmusterung von Filesystemen. Es ist ein grundlegender Bestandteil der Softwareausstattung von UNIX-Systemen und als solcher durch den
POSIX-Standard (beziehungsweise den identischen Standards IEEE Std 1003 und ISO/IEC 9945)[1] definiert, als mandatory (erforderlicher Bestandteil) gekennzeichnet und somit Teil der Single UNIX Specification. Auch UNIX-ähnliche Betriebssysteme verfügen in der Regel über diesen Befehl.
Unter Microsoft Windows gibt es ebenfalls den Befehl find, dieser durchsucht jedoch den Inhalt von Dateien und hat eher (entfernte) Ähnlichkeit mit dem Kommando grep.
Geschichte
Das erste find
erschien in Fifth Edition Unix (ca. Juni 1974) als Teil des PWB/UNIX-Projekts (Programmers Workbench), der in Research Unix[2] übernommen wurde. Es wurde von Richard C. (Dick) Haight, einem Mitglied der PWB/UNIX-Entwickler, geschrieben, ebenso wie cpio und expr.[3] find
und cpio
wurden für den gemeinsamen Einsatz entworfen.
Arbeitsweise
Als typisches Kommandozeilen-Utility ist das Verhalten find
s durch die Sektion 12.2 des Standards (Utility Syntax Guidelines) geregelt.[4] Ausgehend von einem anzugebenden Basisverzeichnis durchschreitet find
die Filesystemstruktur rekursiv und erzeugt eine Liste von Filesystem-Inhalten (Files, Directories etc..), die (wenigstens in den meisten Fällen) auf <stdout>
ausgegeben wird. Diese Liste kann durch einen oder mehrere Operanden nach verschiedenen Gesichtspunkten fortschreitend eingeschränkt werden:
find /some/dir -print # jeden Eintrag in /some/dir anzeigen find /some/dir -type f -print # angezeigte Einträge auf (reguläre) Dateien beschränken find /some/dir -type f -name 'x*' -print # angezeigte Einträge auf Dateien deren Namen mit „x“ beginnt, einschränken
Es ist möglich, mehrere solche Operanden durch logische Operationen (UND, ODER, NICHT) zu verknüpfen wie auch durch Klammern die Präzedenz der Operanden zu beeinflussen. So können auch komplexe Filtertypen realisiert werden.
Allen Operanden ist gemeinsam, dass sie als Ergebnis ein logisches TRUE
oder FALSE
zurückgeben, aufgrund dessen die gerade untersuchte Entität an der weiteren Verarbeitung teilnimmt (bis sie – üblicherweise – am Schluss ausgegeben wird) oder von derselben ausgeschlossen wird.
Es ist möglich, das Ausgabeformat auf den reinen Dateinamen zu beschränken (-print
) oder auch eine Liste von Attributen in Tabellenform (-ls
, was eine Ausgabe ähnlich der des Kommandos ls -ails
bewirkt) auszugeben.
-exec
-exec
Eine besondere Stellung unter den Operanden nimmt -exec
ein. Es erwartet als Argument ein (einfaches oder auch zusammengesetztes) Kommando, in welchem der Name der gerade untersuchten Entität durch das Symbol {}
vertreten wird. Damit ist es möglich, für eine eben erzeugte Liste von Filesystem-Einträgen eine durch ein Kommando repräsentierte Aktion durchzuführen. Das Beispiel sucht in allen Dateien *.c
in dem Directory /some/dir
nach Aufrufen oder dem Code der Funktion myfunc()
(die Datei /dev/null
wird angegeben, damit grep
die Dateinamen der Fundstellen mit anzeigt):
find /some/dir -type f -name '*\.c' -exec grep 'myfunc(' /dev/null {} \;
Darüber hinaus gibt -exec
als Rückgabewert den Return Code des aufgerufenen Kommandos zurück, sodass es ebenfalls für Filterungszwecke genutzt werden kann. Falls im obigen Beispiel nur die Dateinamen der Dateien, in denen die Funktion verwendet wird, gesucht werden, so kann dies durch:
find /some/dir -type f -name '*\.c' -exec grep -q 'myfunc(' {} \; -print
geschehen.
Zeitmessung und -vergleiche
Verschiedene Operanden (-atime
, -ctime
, -mtime
) ermöglichen das Vergleichen von Zeitstempeln von Dateien, wobei die Vergleichszeiträume in Tagen angegeben werden. Tatsächlich werden diese Zeiträume allerdings als Ergebnis einer Integer-Division der Zeitdifferenz in Sekunden durch 86400 interpretiert. Der Standard führt in seinen Erläuterungen als (hier vervollständigtes) Beispiel
find /some/dir -atime 2
an[1], das alle Dateien (oder sonstigen Filesystem-Entitäten) findet, deren Zeitpunkt des letzten Zugriffs zwischen 48 und 72 Stunden vor Ausführung des Befehls liegt.
Hinweise und Einschränkungen
Numerische Argumente
Verschiedene Operanden (zum Beispiel -size
oder -atime
) erwarten numerische Argumente. Bei solchen gilt, dass die Angabe n (für numerische Werte n) immer genau n bedeutet, -n hingegen kleiner als n und +n bedeutet größer als n.
Vorsicht bei -exec
-exec
Da oftmals beim Aufruf von find
nicht feststeht, wie viele Treffer schließlich im Ergebnis-Set vorliegen, kann die Verwendung von -exec
zu einer unverhältnismäßigen Belastung des Systems führen, da ja für jeden Treffer ein (durch vergleichsweise hohen Ressourcenverbrauch gekennzeichneter) fork()-Systemcall durchzuführen ist.
Execplus
Mit dem POSIX-Standard konforme Implementationen kennen deshalb das den externen Aufruf abschließende Plus (+
). Hier wird das externe Kommando mit einer Liste von Treffern gleichzeitig aufgerufen, sodass die erwähnte Belastung des Systems durch viele fork()-s verringert wird. Gleichzeitig aber wird der Rückgabewert des Kommandos für eine einzelne Datei unbestimmt, sodass -exec
nicht mehr weiter als filternder Operand wirken kann.
Weitere Probleme bei der Verwendung von -exec
können sich bei komplexen Kommandos ergeben: es ist zwar grundsätzlich möglich, verschachtelte Kommandos zu verwenden, aber letztlich ist find
keine Shell und deshalb in der Interpretation solcher Schachtelungen beschränkt. Insbesondere Shell-übliche Konstruktionen wie etwa die logische Verknüpfung cmd1 && cmd2 schlagen innerhalb von Kommandos in -exec
fehl.
{}
und -exec
{}
und -exec
Das Argument {}
kann lediglich ein einziges Mal in einem -exec
-Operanden verwendet werden, nicht öfter. Darüber hinaus muss es als einzelnes (das heißt alleinstehendes) Argument verwendet werden. Die folgenden Konstruktionen sind deshalb alle ungültig:
find /some/where -type f -exec mv {} {}.old \; find /some/where -type f -exec gzip {} >/packed/files/{} \;
Für solche Zwecke sollte ein Script geschrieben werden, dem als Parameter der Dateiname übergeben wird und das als Argument in -exec
eingesetzt wird. Etwa für das erste Beispiel:
$ cat > /tmp/mymove.sh <<EOF mv $1 ${1}.old EOF
$ find /some/where type f -exec /tmp/mymove.sh {} \;
Schutz vor unendlichem Regress
In der Praxis kann es durchaus vorkommen, dass in Filesystemen (durch Hardlinks oder Softlinks) Endlosreferenzen aufgebaut werden. Der POSIX-Standard schreibt deshalb vor, dass konforme Versionen diesen Umstand zu erkennen und die Rekursion abzubrechen haben.[1]
Nonstandard-Varianten
Das GNU-Projekt verfügt über einen Nachbau des Kommandos als Teil des findutils-Pakets. Es unterscheidet sich vom POSIX-konformen Original in einigen Punkten.
Weblinks
find(1)
: find files – Open Group Base Specificationfind(1)
: in einer Verzeichnishierarchie nach Dateien suchen – Debian GNU/Linux Ausführbare Programme oder Shell-Befehle Handbuchseitefind(1)
: walk a file hierarchy – OpenBSD General Commands Manual- Linux and Unix find command tutorial with examples (engl.)
Einzelnachweise
- find (Opengroup Base Specifications Issue 6). Abgerufen am 8. März 2018 (englisch).
- Die Bezeichnung wurde allerdings erst ab 1978 für diese Entwicklungslinie gebräuchlich, um sie von PWB/UNIX und MERT abzugrenzen, siehe Bell System Technical Journal Vol. 57, No 6, Pt. 2 Jul/Aug 1978
- M. Douglas McIlroy: A Research Unix reader: annotated excerpts from the Programmer's Manual, 1971–1986. (pdf) Abgerufen am 8. März 2018 (englisch).
- The Open Group Base Specifications Issue 7, 2018 edition, Kap. 12. Utility Conventions. Abgerufen am 15. Mai 2019 (englisch).