Unix bietet mächtige Programme an, um Dateien im Dateisystem zu finden und deren Typ zu erkennen. Diese beiden, hier besprochenen Befehle sind auf allen Unix-Systemen der Welt zu finden und gehören zu den wichtigsten Werkzeugen des Systemverwalters. Aber auch versierte Normaluser nutzen diese Programme oft und gerne…

Datein finden mit find

Unix hat zwar nur einen Dateibaum, der kann aber ausgesprochen komplex aufgebaut sein und manchmal hunderttausende von Dateien in tausenden von Verzeichnissen enthalten. Es ist daher nötig, diese Dateien nach bestimmten Kriterien suchen zu können, ohne von Hand die einzelnen Verzeichnisse zu „durchwandern“.

Diese Aufgabe wird vom Befehl find erledigt. find bietet aber neben der Fähigkeit Dateien zu suchen auch noch an, beliebige Aktionen mit den gefundenen Dateien auszuführen. Aus diesem Grund ist dieses Programm ein unentbehrliches Hilfsmittel für den Systemvewalter.

Die genauen Parameter, Tests und Aktionen von find sind auf der Handbuchseite aufgelistet, hier soll noch einmal in Beispielen erklärt werden, wie find aufgerufen wird und wie man damit vernünftig arbeiten kann.

Die einfache Aufrufform von find ist

find   Startverzeichnis   Test   Aktion

Dabei sucht find alle Verzeichnisse ab Startverzeichnis nach den Dateien ab, für die die Kriterien Test zutreffen. Für jede gefundene Datei wird dann die Aktion durchgeführt. Wenn die Aktion weggelassen wird, so wird standardmäßig die Aktion -print ausgeführt, d.h. der Dateiname der gefundenen Datei wird zusammen mit seinem Suchpfad (relativ zum angegebenenen Startverzeichnis) ausgegeben.

Um Dateien anhand ihres Namens zu finden, wird der Test -name Muster benutzt. Wenn der Name nicht vollständig bekannt ist, oder nach verschiedenen Dateien mit bestimmten Namen gesucht werden soll, dann kann das Suchmuster auch die Jokerzeichen verwenden, die auch die Shell benutzt (*,?,[…]). Aber Vorsicht: Das Namensmuster muß dann in Anführungszeichen gesetzt werden, weil sonst die Shell die Jokerzeichen interpretieren und durch evt. gefundene Dateien im aktuellen Verzeichnis ersetzen würde.

Um also z.B. alle Dateien des gesamten Systems zu finden, deren Namen mit einem großen oder kleinen M beginnt schreiben wir:

find / -name "[mM]*"

Der Slash steht für das Startverzeichnis, hier also das Wurzelverzeichnis. -name leitet den Namenstest ein und „[mM]*“ ist das Suchmuster. Die Aktion haben wir hier einfach weggelassen, es wird also die -print Aktion durchgeführt. Das Ergebnis sieht dann etwa so aus:

 
/usr/X11R6/bin/macptopbm
/usr/X11R6/bin/mgrtopbm
/usr/X11R6/bin/mtvtoppm
/usr/X11R6/bin/makedepend
/usr/X11R6/bin/makeg
/usr/X11R6/bin/mergelib
/usr/X11R6/bin/mkdirhier
/usr/X11R6/bin/mkfontdir
/usr/X11R6/bin/mksusewmrc
/usr/X11R6/bin/manix
/usr/X11R6/bin/mirrormagic
/usr/X11R6/bin/mogrify
/usr/X11R6/bin/montage
/usr/X11R6/bin/mtv
/usr/X11R6/bin/mtvp
/usr/X11R6/bin/mpeg_play
/usr/X11R6/include/GL/MesaDrawingArea.h
/usr/X11R6/include/GL/MesaDrawingAreaP.h
/usr/X11R6/include/GL/MesaMDrawingArea.h
/usr/X11R6/include/GL/MesaMDrawingAreaP.h
/usr/X11R6/include/GL/MesaWorkstation.h
/usr/X11R6/include/GL/MesaWorkstationP.h
/usr/X11R6/include/X11/Xaw3d/MenuButtoP.h
...

Wenn mit Tests gearbeitet wird, die nummerische Parameter haben, dann gibt es eine Besonderheit. Wird die Zahl einfach, ohne Vorzeichen angegeben, dann heißt das, dass genau diese Zahl gemeint ist. Hat die Zahl als Vorzeichen ein Pluszeichen (+), dann heißt das, dass die Zahl oder eine größere Zahl gemeint ist, ein Minuszeichen bedeutet entsprechend die Zahl oder eine kleinere.

Der Test -size sucht Dateien nach ihrer Größe. Schreiben wir also

find . -size 12k

so sucht find nach allen Dateien im aktuellen Verzeichnis (.), die genau 12 Kilobyte groß sind. Wenn wir alle Dateien suchen, die höchstens 12 Kilobyte groß sind, so schreiben wir

find . -size -12k

und Dateien, die mindestens 12 Kilobyte groß sind finden wir mit

find . -size +12k

Wenn wir mehrere Tests angeben, so werden die Dateien gesucht, auf die alle Tests zutreffen, nicht die, die einen von beiden Tests bestehen. Der Befehl

find . -size +12k -name "M*"

sucht also nach allen Dateien im aktuellen Verzeichnis, die mindestens 12 Kilobyte groß sind UND deren Namen mit einem M beginnt.

Richtig interessant wird find erst mit der Anwendung von Aktionen. Die wichtigste und sicherlich meistgebrauchte Aktion ist -exec. Mit dieser Aktion lassen sich beliebige Unix-Kommandos ausführen, die mit den gefundenen Dateien angewendet werden. Dabei gibt es zwei wichtige Punkte zu beachten.

  1. Die Befehlszeile der -exec Aktion muß mit einem \; abgeschlossen werden, damit eindeutig klar wird, was ist Befehlszeile und was weitere Aktionen. Der Strichpunkt muß mit einem Backslash versehen sein, damit ihn die Shell nicht interpretiert. Außerdem muß er durch ein Leerzeichen von der Befehlszeile getrennt sein.
  2. Der Namen der gefundenen Datei wird mit einem {} dargestellt. Trifft find auf eben diese zwei geschweiften Klammern, so ersetzt es diese durch den gefundenen Dateinamen.

Um also etwa alle Dateien des ganzen /usr Verzeichnisses, die größer als 12 Kilobyte sind und deren Namen mit M beginnt in das Verzeichnis /tmp zu kopieren schreiben wir:

find /usr -size +12k -name "M*" -exec cp {} /tmp \;

Oder, um ein etwas praktischeres Beispiel zu nennen, wenn der Systemverwalter alle Dateien löschen will, die Usern gehören, die es nicht mehr gibt, dann kann er schreiben:

find / -nouser -exec rm {} \;

Das ist zweifellos ein gewisses Risiko, es könnten ja auch wichtige Dateien dabei sein, die durch einen Zufall einer UserID zugewiesen wurden, die nicht bekannt ist. Statt -exec können wir in so einem Fall auch -ok benutzen. Es macht exakt genau das Gleiche wie -exec, fragt aber bei jeder Ausführung vorher nach, ob es die Befehlszeile wirklich ausführen soll.

Dateitypen erkennen mit file

Unix benutzt nicht die Mechanismen wie DOS/Windows, dass Dateitypen anhand der Endung des Dateinamens erkannt und unterschieden werden. Dieser Mechanismus ist ja auch sehr primitiv und fehleranfällig, nichts ist leichter, als einen Computer unter DOS abstürzen zu lassen, indem man einer Textdatei die Namenserweiterung .com gibt und sie „aufruft“…

Unter Unix werden Dateien nach inhaltlichen Kriterien unterschieden, nicht nach Namen. Dazu gibt es den Befehl file. Dieser Befehl ließt die ersten Zeilen einer Datei und versucht anhand einer Datenbank festzustellen, um was für einen Typ Datei es sich dabei handelt.

Die meisten Dateitypen sind sehr einfach anhand ihrer ersten Bytes zu erkennen. Diese ersten Bytes enthalten fast immer bestimmte Kennwörter oder -zahlen, die eine eindeutige Zuordnung ermöglichen. Diese Kennzeichen sind in der Datei /etc/magic gespeichert. Oft ist diese Datei nur ein Link auf /usr/lib/magic.

Die Datei magic enthält also Zeile für Zeile Beschreibungen, die zeigen, um welche Datei es sich handelt, wenn an einer bestimmten Position (offset) innerhalb der Datei eine bestimmte 1, 2 oder 4 Byte Zahl oder eine bestimmte Zeichenkette zu finden ist.

file sucht solange nach einem passenden Eintrag, bis das Ende der Datei erreicht ist. Wird kein passender Eintrag gefunden und die Datei nicht als ASCII-Textdatei erkannt, so wird das Ergebnis „data“ ausgegeben.

Das Programm file wird seltener direkt aufgerufen, aber sehr häufig von Shellscripts o.ä., um bestimmte Dateien zu analysieren und so z.B. herauszufinden, mit welchem Filter sie gedruckt werden können.

Ein großer Vorteil der Architektur der Datei /etc/magic ist die Erweiterbarkeit. Wenn zum Beispiel ein neues Programm entwickelt wird, dessen Datendateien ein bestimmtes Format aufweisen, so muß nur ein entsprechender Eintrag in der Datei /etc/magic gemacht werden, und schon erkennt file die Datei korrekt.