[[Vorlage(Getestet, general)]] {{{#!vorlage Wissen [:Terminal: Ein Terminal öffnen] [:Shell:Was ist und wie benutzt man eine Posix-Shell?] }}} [[Inhaltsverzeichnis]] [[Bild(Wiki/Icons/terminal.png, 48, left)]] Das Kommandozeilenprogramm '''find''' findet Dateien mit bestimmten vorgebbaren [#Tests Kriterien] in ganzen Verzeichnisbäumen ab angegebenen [#Startpunkte Startpunkten]. Dabei kann es die Suche auf vielfältige Weise filtern, z.B. nach Dateiname, -alter, -größe und die Suchergebnisse formatiert ausgeben und/oder weiter verarbeiten. Da unter unixartigen Systemen der Leitsatz ''„Alles ist eine Datei“'' gilt, werden auch Verzeichnisse und andere in der Dateihierarchie eingetragene Dateitypen (z.B. Sockets) gefunden. Der Einfachheit halber meint in diesem Artikel das Wort „Datei“ meistens jedes von find gefundene Ergebnis unabhängig von dessen konkretem Dateityp. = Alternativen = Das Programm find ist wegen seiner zahlreichen Suchkriterien sehr mächtig und daher fast immer das Mittel der Wahl, wenn es darum geht, auch Unterverzeichnisse zu durchsuchen bzw. eine Menge von über die Suchkriterien bestimmten Dateien zu bearbeiten. Wegen seiner Mächtigkeit kann es aber auch schwer anwendbar sein. In manchen Situationen kommt man daher mit anderen Methoden schneller oder einfacher zum Ziel: * Wenn man den Dateinamen genau kennt, kann [:locate:] eine bessere Wahl sein. Das Programm `locate` arbeitet allerdings mit einem nur täglich aktualisierten Index und findet daher ganz frische Dateien nicht. * Für die spezielle Suche nach Programmen kann man `which` oder `whereis` benutzen: * Das Programm `which` findet den Speicherort eines über die [:Umgebungsvariable:] `PATH` auffindbaren Programms. * Das Programm `whereis` findet ebenfalls den Speicherort und zusätzlich den Quelltext und die Manpages, sofern vorhanden. * Im aktuellen Verzeichnis, ohne Unterverzeichnisse zu berücksichtigen, kommt man mit [:Terminal#Vervollstaendigen-lassen-nicht-tippen:automatischer Vervollständigung] und den Jokerzeichen `*` und `?` oft weiter, wenn man Namensbestandteile kennt. Manche Programme bieten auch von sich aus an, Unterverzeichnisse zu berücksichtigen, siehe [:ls:] und [:grep:]. * Wer lieber in der [wikipedia:GUI:grafischen Oberfläche] nach Dateien suchen möchte, kann eine [:Desktopsuchmaschinen:Desktopsuchmaschine] verwenden. Diese sind teilweise spezifisch für den jeweiligen Desktop und berücksichtigen bei der Suche auch die Meta-Daten der Dateien. = Installation = Das Programm ist in den offiziellen Paketquellen von Ubuntu enthalten und wird auf jedem System installiert. {{{#!vorlage Paketinstallation findutils, Programme zum Suchen nach Dateien - find, xargs, aus main }}} Dieser Artikel beschreibt die vorstehende Version. Es gibt allerdings auch eine neue Implementierung namens '''rust-findutils''', die experimentierfreudige Anwender optional aus ''universe'' installieren können und verspricht, das traditionelle find 1:1 zu ersetzen. = Aufruf = Im Terminal[1] verwendet man das Programm mit dieser generellen Syntax: {{{#!vorlage Befehl find OPTIONen STARTPUNKTe TESTs AKTIONen }}} Ein Aufruf kann ziemlich komplex werden; hier ein konkretes Beispiel: {{{#!vorlage Befehl find -P ~ -xdev -type f -printf '%s\t%k\t%p\n' | sort -g -r | head -n 5 }}} In diesem Beispiel ist „`-P`“ eine OPTION, „`~`“ der STARTPUNKT, „`-xdev -type f`“ sind die TESTs und „`-printf '%s\t%k\t%p\n'`“ die AKTION. Es ist nicht unüblich, die Ausgabe von find per Pipe weiterzuleiten an andere Programme, wie auch in diesem Beispiel gezeigt. Das Beispiel ermittelt die 5 größten regulären Dateien im [:Homeverzeichnis:] des Benutzers, dabei werden [:ln:symbolische Links] und eingebundene Dateisysteme nicht berücksichtigt; weitere Erklärungen siehe späteren Abschnitt [#Beispiele Beispiele]. * [#Optionen OPTIONen] ist eine möglicherweise leere Folge von Angaben nach Tabelle 1. * [#Startpunkte STARTPUNKTe] ist eine möglicherweise leere Liste von Dateinamen. Das Programm prüft jeden Namen, ob eine Datei mit diesem Namen existiert und nimmt dann diese Datei als einen Startpunkt für seine Suche oder erzeugt anderenfalls eine Fehlermeldung, bearbeitet aber andere Namen in der Liste. Ein Startpunkt ist im Regelfall ein Ordner in der Dateihierarchie, andere Dateitypen sind möglich, aber selten sinnvoll. Bei Angabe mehrerer Startpunkte werden diese nacheinander abgearbeitet. Das Programm untersucht alle Dateien ab jedem angegebenen Startpunkt und bei Ordnern auch rekursiv alle enthaltenen Dateien. Wenn man keinen Startpunkt angibt, gilt das Verzeichnis „'''.'''“ als Startpunkt. * [#Tests TESTs] ist eine möglicherweise leere Folge von Suchkriterien nach Tabelle 2. Alle Tests werden mit „Und“ verknüpft, d.h. es werden nur die Dateinamen von Dateien, die alle Tests bestehen, an die AKTIONen weiter gegeben – diese Verknüpfung kann man wie unter [#Kombinationen Kombinationen] beschrieben ändern. Wenn man keinen Test angibt, werden alle Dateien ausgewählt. * [#Aktionen AKTIONen] ist eine möglicherweise leere Folge von Operationen nach Tabelle 5, die an den über die Tests selektierten Dateien ausgeführt werden sollen – man kann z.B. Dateinamen listen, Dateien löschen oder Dateinamen als Argumente an beliebige andere Programme übergeben. Wenn man keine Aktion angibt, wird als Standardaktion `-print` ausgeführt. * Tests und Aktionen kann man auch mischen. Das Programm optimiert die angegebene Reihenfolge in einer durch [#Optionen Optionen] beeinflussbaren Weise. * Es sind außerdem unter Tests und Aktionen noch einige spezielle Angaben möglich, die die Dokumentation des Programms als [#Tabelle-3a ''"global options"''], [#Tabelle-3b ''"positional options"''] und als [#Kombinationen ''"operators"''] beschreibt und in diesem Artikel auszugsweise unter [#Tests Tests] mit besprochen werden, da sie wie diese angewendet werden. Diese speziellen Angaben modifizieren entweder generell die Arbeitsweise des Programms oder die Funktion einzelner Tests; ein Beispiel dafür ist `-help`: [[Vorlage(Befehl, 'find -help' ) ]] [[Anker( RTFM ) ]] Weitere Details kann man dem [:man:Manual] (Manpage) des Programms entnehmen: * Auf dem eigenen Rechner: [[Vorlage(Befehl, 'man find' ) ]] * oder Ubuntu Manuals im Internet zu [man_de:find:] {en} Noch weiter informativ sind * auf dem eigenen Rechner die [:info:Infoseiten] zu find: [[Vorlage(Befehl, 'info find' ) ]] und * die sehr ausführliche Seite zu [http://www.gnu.org/software/findutils/manual/html_mono/find.html findutils auf gnu.org] {en}. = Suchstrategie = Das Programm durchläuft die Dateinamensbäume ab den Startpunkten als Wurzeln rekursiv und, sofern man das nicht selbst begrenzt, vollständig nach einer von zwei möglichen Strategien: 1. „Breite vor Tiefe“: Gefundene Ordner werden nach der Behandlung von regulären Dateien und anderen Dateitypen als letztes durchsucht. 1. „Tiefe vor Breite“: Gefundene Ordner werden sofort durchsucht, also vor regulären Dateien und anderen Dateitypen behandelt. Bei jeden Aufruf von find wird die Suchstrategie einmalig vor dem Beginn der Suche durch Analyse der Kommandozeile bestimmt und dann nicht mehr verändert. Die Auswahl der Strategie ändert nicht, was gefunden wird, sondern nur die Reihenfolge, in der es gefunden und ggf. gelistet wird. Vorgabe ist „Breite vor Tiefe“, sofern man weder bei [#Tests Tests] `-depth` noch die [#Aktionen Aktion] `-delete` angibt. Jedes dieser beiden Schlüsselworte aktiviert „Tiefe vor Breite“. = Optionen = {{{#!vorlage Tabelle <-2 rowclass="titel">Tabelle 1: Optionen +++ Kriterium Beschreibung +++ `-H`[[BR]]`-L`[[BR]]`-P` Diese Optionen schließen sich gegenseitig aus, d.h. wenn man mehrere angibt, wird nur die letzte Angabe wirksam. Wenn man keine angibt, gilt als Vorgabe `-P`.[[BR]] Diese Optionen bestimmen den Umgang des Programms mit Dateien vom Typ [:ln:symbolischer Link], die mit `-P` stets ignoriert werden und mit `-L` stets berücksichtigt und verfolgt werden sowie mit `-H` manchmal beachtet werden. +++ `-D DEBUG-OPTS` `DEBUG-OPTS` ist eine mit Kommata getrennte Liste von einem oder mehreren möglichen Begriffen, die man sich mit [[Vorlage(Befehl, 'find -D help') ]] anzeigen lassen kann. Mit dieser Option erhält man zusätzlich zum normalen Arbeitsergebnis für die angegebenen Bereiche Diagnoseinformationen auf dem Standardfehlerkanal. +++ `-O0` oder`-O1` Diese beiden Optionen sind gleichwertig und `-O1` ist die Vorgabe. Die Reihenfolge von Tests wird automatisch so optimiert, dass Filterungen nach Dateinamen zuerst erfolgen. +++ `-O2` Zusätzlich zur ersten Stufe werden auch Filterungen nach dem Dateityp (Tests `-type` und `-xtype`) so früh wie möglich, aber nach den Tests für Dateinamen ausgeführt. +++ `-O3` Es werden zusätzlich zur zweiten Stufe weitere Optimierungen aktiviert. }}} Soll auch in verlinkten Ordnern (sowohl absolut, als auch rekursiv) im angegebenen Suchpfad gesucht werden, so ist beim Programmaufruf ein `-L` anzufügen. Dieses muss jedoch vor den Suchpfad: * [[Vorlage(Befehl, 'find -L .' ) ]] sucht im aktuellen Verzeichnis, folgt gefundenen symbolischen Links und schließt auch Funde aus verlinkten Verzeichnissen in das Ergebnis ein. = Startpunkte = Startpunkte geben an, wo gesucht wird, nicht was gesucht wird. Ist keiner angegeben, wird im aktuellen Arbeitsverzeichnis gesucht. Startpunkte müssen __nach__ [#Optionen Optionen] und __vor__ den ebenfalls optionalen [#Tests Suchkriterien] und [#Aktionen Aktionen] platziert werden. In den meisten Fällen wird es sich dabei um Verzeichnisse handeln, andere Dateitypen sind aber auch erlaubt. Wenn nicht die ganzen gegebenenfalls dort darunter liegenden Verzeichniszweige durchsucht werden sollen, kann die Durchsuchungstiefe mit [#Sonstige-Suchkriterien zusätzlichen Suchkriterien] begrenzt werden. * [[Vorlage(Befehl, 'find' ) ]] ist äquivalent zu: [[Vorlage(Befehl, 'find -P . -print' ) ]] Das Programm sucht also im aktuellen Verzeichnis, ignoriert symbolische Links und findet dort alle Einträge, deren Dateinamen mit vollständigen Pfad ab Startpunkt ausgegeben wird. Dazu gehört auch der Hardlink „'''.'''“ im Startpunkt „'''.'''“ als Ordner. * [[Vorlage(Befehl, "find foo" ) ]] setzt den Startpunkt auf den Eintrag '''foo''' im aktuellen Arbeitsverzeichnis, und sofern dieser Startpunkt existiert und ein Ordner ist, wird darin gesucht und die Namen aller darin enthaltenen Dateien werden gelistet. * [[Vorlage(Befehl, 'find ../' ) ]] sucht im übergeordneten Verzeichnis. * [[Vorlage(Befehl, 'find /tmp' ) ]] sucht im absolut angegebenen Verzeichnis '''/tmp'''. * [[Vorlage(Befehl, 'find /tmp /boot' ) ]] sucht in zwei Verzeichnissen, also sowohl in '''/tmp''' als auch in '''/boot'''. * [[Vorlage(Befehl, 'find /' ) ]] sucht ab dem Wurzelverzeichnis '''/''' das gesamte Dateisystem -- was lange dauern kann. * [[Vorlage(Befehl, 'cd ; find V*' ) ]] wechselt ins Home-Verzeichnis und die aufrufende Shell wertet dort den [:Shell/Glob:Glob] `V*` aus. Normalerweise gibt es dort die Order '''Videos''' und '''Vorlagen''' und dann ist für `find` der Aufruf äquivalent zu: [[Vorlage(Befehl, 'find -P Videos Vorlagen -print' ) ]] Die beiden Startpunkte werden durchsucht und alle darin enthaltenen Einträge gelistet. \\ {{{#!vorlage Hinweis Beachte: Das Jokerzeichen `*` wird hier von der aufrufenden Shell[2] und nicht von find ersetzt. In der Regel ist dies bei Startpunkten die sinnvolle Arbeitsweise. Das Programm `find` kann aber bei Tests und bei Aktionen auch selber mit Jokerzeichen umgehen, die ihm dann aber quotiert oder maskiert übergeben werden müssen. }}} [[Anker( Tests ) ]] = Suchkriterien = {{{#!vorlage Tabelle <-2 rowclass="titel">Tabelle 2: Ausgewählte Tests bzw. Suchkriterien +++ Kriterium Beschreibung +++ `-name MUSTER` sucht Dateinamen, die dem Muster `MUSTER` entsprechen. `MUSTER` ist ein [:Shell/Glob:Shell-Glob], kann also Jokerzeichen wie „`*`“ und „`?`“ enthalten, die dann immer quotiert oder maskiert werden müssen, damit die aufrufende Shell sie __nicht__ interpretiert. Beispiele: „`\*.txt`“ oder „`'???.t*xt'`“. `MUSTER` kann den Schrägstrich „`/`“ nicht enthalten und `-name` untersucht nur den Eigennamen, nicht den Pfad zur Datei. +++ `-iname MUSTER` arbeitet wie `-name`, aber ohne Beachtung der Groß- und Kleinschreibung. +++ `-path MUSTER` arbeitet ähnlich wie `-name`, untersucht aber auch den Pfad zur Datei und `MUSTER` darf daher auch den Schrägstrich enthalten. +++ `-ipath MUSTER` arbeitet ähnlich wie `path`, aber ohne Beachtung der Groß- und Kleinschreibung. +++ `-regex REGEX`[[BR]]`-iregex REGEX` arbeiten ähnlich wie `-path` bzw. `-ipath`, aber das Suchmuster ist nicht als Shell-Glob, sondern als regulärer Ausdruck anzugeben. Es werden standardmäßig reguläre Ausdrücke mit der Syntax von Emacs erwartet, das kann man mit `-regextype` ändern. +++ `-type T` selektiert Dateien nach ihrem Typ. `T` ist ein Kennbuchstabe zur Angabe des Typs, dabei steht `f` (= file) für reguläre Dateien, `d` (= directory) für Verzeichnisse und `l` für symbolische Links; weitere siehe [#RTFM Dokumentation]. Man kann für `T` auch eine mit Kommata getrennte Liste von Kennbuchstaben angeben, wenn man nach mehreren Typen gleichzeitig suchen will. +++ `-size N` selektiert Dateien nach ihrer Größe: `N` ist eine ganze Zahl mit optionalem Vorzeichen (`-`, keines, `+`) und angehängtem Multiplikator (`c` für Byte, `k` für KiB (Kibibyte), `M` für MiB, `G` für GiB), z.B. `-42k`, `42k`, `+42k`, `2M`) Syntaktisch ist der Multiplikator optional, jedoch wird in der Praxis immer einer verwendet, denn die Voreinstellung `b` für 512 Byte ist leider nicht praxisgerecht. Der wirksame Zahlenbereich ändert sich mit Vorzeichen und Multiplikator, d.h. `4096c` ≠ `4k` usw! Näheres siehe [#Groesse Größe] und [#find-rechnet-seltsam find rechnet seltsam]. +++ `-empty` sucht leere Dateien inkl. Ordner, also solche ohne Inhalt. +++ `-Xtime N`[[BR]]`-Xmin N` selektieren Datei nach dem Zeitpunkt ihrer letzten Änderung oder Verwendung. `X` ∈ { a, c, m } bestimmt den abzufragenden Zeitstempel, `N` ist eine ganze Zahl mit optionalem Vorzeichen (`-`, keines, `+`), aber ohne angehängten Multiplikator, weil sich dieser aus dem Namen des Tests ergibt. Details siehe [#Alter Alter] und [#find-rechnet-seltsam find rechnet seltsam]. +++ `-newer DATEI` sucht nach Dateien, deren Inhalt nach dem von `DATEI` verändert wurde. +++ `-cnewer DATEI` sucht nach Dateien, deren Verwaltungsdaten nach denen von `DATEI` verändert wurde. +++ `-newerXY DATEI` sucht nach Dateien, deren Zeitstempel `X` nach dem Zeitstempel `Y` von `DATEI` verändert wurde. `X`, `Y` ∈ { a, c, m } +++ `-newerXt ZEITSPEZ` sucht nach Dateien, deren Zeitstempel `X` nach der Zeitangabe `ZEITSPEZ` verändert wurde. Details siehe [#newerXt Text]. +++ `-user BESITZER`[[BR]]`-group GRUPPE` sucht nur nach Dateien, die dem Benutzer `BESITZER` bzw. der Gruppe `GRUPPE` gehören. `BESITZER` bzw. `GRUPPE` kann ein Name oder eine numerische Kennung UID bzw. GID sein. +++ `-uid N`[[BR]]`-gid N` arbeitet ähnlich wir vorstehende Tests, jedoch muss man als `N` eine numerische Kennung UID bzw. GID mit optionalem Vorzeichen angeben. Damit kann man dann auch z.B. nach „alle Benutzer mit kleinerer UID als N“ suchen. +++ `-nouser` sucht nach Dateien, deren numerische Besitzer-Kennung keinem dem System bekannten Benutzer entspricht. +++ `-nogroup` sucht nach Dateien, deren numerische Gruppen-Kennung keiner dem System bekannten Gruppe entspricht. }}} Es gibt einige Optionen, die wie Tests verwendet werden, aber dann nicht die einzelnen Dateien beurteilen, sondern die Suche generell modifizieren. Es ist besser, diese Optionen lt. folgender Tabelle 3a zum Beginn der Tests anzugeben, denn sonst meckert find eine [#Warnungen Warnung], macht aber trotzdem das, was es für richtig hält und das ist möglicherweise nicht das, was der Bediener haben wollte. Außerdem gibt es als Tests geschriebene positionelle Optionen nach Tabelle 3b, welche die Arbeitsweise ihnen folgender Tests modifizieren. [[Anker( Tabelle-3a ) ]] {{{#!vorlage Tabelle <-2 rowclass="titel">Tabelle 3a: Globale Optionen +++ Kriterium Beschreibung +++ `-help` zeigt eine Kurzanleitung des Programms. Es wird nicht gesucht. +++ `-maxdepth n` sucht ab dem [#Startpunkt-e Startpunkt] nur n (ganze Zahl ≥ 0) Verzeichnisse tief. Bezeichnet dieser ein Verzeichnis – z.B. implizit das aktuelle Verzeichnis – zählen dessen Einträge schon zu Tiefe 1. +++ `-mindepth n` durchsucht zwar alles, ignoriert aber alle Dateien mit kleinerer Verzeichnistiefe als angegeben. +++ `-depth` sucht erst rekursiv im Inhalt der Verzeichnisse, bevor das Verzeichnis selbst untersucht wird. (Standard bei `-delete` Aktion) :arrow: [#Suchstrategie Suchstrategie] +++ `-xdev`[[BR]]--(`-mount`)-- Order von anderen eingebundenen Dateisystemen werden nicht durchsucht.[[BR]]Das bei GNU find veraltete Synonym `-mount` soll man vermeiden. }}} [[Anker( Tabelle-3b ) ]] {{{#!vorlage Tabelle <-2 rowclass="titel">Tabelle 3b: Positionelle Optionen +++ Kriterium Beschreibung +++ `-daystart` misst für alle (!) darauf folgenden `-Xtime`- und `-Xmin`-Kriterien ab 00:00 h des aktuellen Tages, also ab Mitternacht. Einmal eingeschaltet, lässt sich dieser Modus nicht mehr ausschalten. +++ `-regextype TYPE` ändert für folgende Texts mit `regex` den Typ des regulären Ausdrucks. Zulässige Typen listet [[Vorlage(Befehl, 'find -regextype ?' ) ]] }}} {{{#!vorlage Hinweis Die in diesem und folgenden Kapiteln ab diesem Hinweis gezeigten Beispiele enthalten fast alle einen Punkt „`.`“ nach dem Programmnamen. Das soll den Leser daran erinnern, dass an dieser Stelle von ihm ein selbst gewählter [#Startpunkte Startpunkt] oder eine Folge von Startpunkten einzusetzen ist, ab dem/denen gesucht werden soll. Man kann allerdings die Befehle auch genau so wie gezeigt verwenden und sie arbeiten dann im aktuellen Arbeitsverzeichnis (''working directory''). Schließlich kann man den Punkt auch weglassen, weil find eine leere Folge von Startpunkten automatisch und stillschweigend durch den Punkt ersetzt. }}} == Name == * [[Vorlage(Befehl, 'find . -name hausarbeit.odt' ) ]] sucht nach Dateien mit dem vollständigen Namen '''hausarbeit.odt'''. * [[Vorlage(Befehl, 'find . -name "*.pdf"' ) ]] sucht nach PDF-Dateien. Der Test `-name` berücksichtigt die Groß-/Kleinschreibung, findet hier also keine Datei(en) mit Endung '''*.PDF'''. * [[Vorlage(Befehl, 'find . -iname a\*.pdf' ) ]] sucht nach '''.pdf'''- und '''.PDF'''-Dateien, die mit `a` oder `A` beginnen (ignoriert die Groß-/Kleinschreibung). * [[Vorlage(Befehl, 'find . -name "katze.*"' ) ]] findet '''katze.jpg''', '''katze.png''', '''katze.txt''', '''katze.frisst_die_Maus''' usw. * [[Vorlage(Befehl, 'find . -name "katze.??g"' ) ]] findet '''katze.jpg''', '''katze.png''' usw. (jedes Fragezeichen steht für ein einzelnes Zeichen). * [[Vorlage(Befehl, 'find . -name "*foo*.*x*"' ) ]] findet '''foo.x''', '''afoo.x''', '''foob.txt''' usw. == Pfad == Will man die Suche auf bestimmte Pfade einschränken, kommt man mit `-name` nicht weiter. Das Suchkriterium `-path` ist hier die Lösung, denn es erlaubt die Verwendung des die Namen trennenden Schrägstrichs `/`. * [[Vorlage(Befehl, 'find . -path "*2013/J*"' ) ]] findet '''~/Bilder/2013/Juni''' und '''~/Musik/2013/Juli''', aber nicht '''~/Dokumente/2013-Juni'''. * Pfade ausschließen: [[Vorlage(Befehl, 'find ~ -path ~/Dokumente -prune -or -path ~/Downloads -prune -or -iname "*.pdf" -print -or -iname "*.tif*" -print' ) ]] findet alle PDF- und TIFF-Dateien im Homeverzeichnis außer die in '''~/Dokumente/''' und '''~/Downloads/'''. Das explizite `-print` ist nötig, da `-prune` nicht nur die Suche im jeweiligen Pfad sondern auch die Ausgabe zunächst abbricht. * Nicht lesbare Pfade ausschließen (vermeidet zahlreiche Fehlermeldungen): [[Vorlage(Befehl, 'find / ! -readable -prune -o -name "*.desktop" -print' ) ]] == Typ == * [[Vorlage(Befehl, 'find . -type f' ) ]] findet nur reguläre Dateien. Verzeichnisse, Sockets, etc. werden ausgelassen. * [[Vorlage(Befehl, 'find . -type d' ) ]] findet nur Verzeichnisse (Typ: directory). == Größe == Man kann nach Dateien suchen, die kleiner, exakt gleich oder größer als ein vorgebbarer Vergleichswert sind, dabei wird der Vergleichsoperator durch das Vorzeichen des Vergleichswertes bestimmt: * [[Vorlage(Befehl, 'find . -size -4096c -ls' ) ]] Mit dem Vorzeichen „`-`“ werden alle Dateien gefunden, die kleiner als 4096 Byte bzw. 4 KibiByte sind. * [[Vorlage(Befehl, 'find . -size 4096c -ls' ) ]] Ohne Vorzeichen wird auf exakte Gleichheit geprüft. * [[Vorlage(Befehl, 'find . -size +4096c -ls' ) ]] Mit dem Vorzeichen „`+`“ werden alle Dateien gefunden, die größer als 4096 Byte bzw. 4 KibiByte sind. Bei diesen Befehlen ist die Angabe des Multiplikators „`c`“ wichtig, denn sonst [#Numerische-Angaben rechnet find seltsam]. „`c`“ bedeutet `character`, welche früher 1 Byte belegten (`b` ist schon für die Maßeinheit Block (= 512 Bytes) vergeben). Mittels dem zusätzlichen `-ls` lässt sich die Größe der gefundenen Dateien überprüfen. Deswegen wird es hier, vor den anderen [#Aktionen Aktionen], erwähnt. Vorgenannte Befehle funktionieren mit jeder Anzahl von Bytes. Bei großen Schwellen kann man auch die Multiplikatoren `k` für Kibibytes (1024), `M` für Mebibytes (1024^^(2)^^) oder `G` für Gibibytes (1024^^(3)^^) angeben, wegen der [#Numerische-Angaben ungewöhnlichen Rechenweise] sollte man das nur in folgender Art und Weise tun: * [[Vorlage(Befehl, 'find . -size +4096c -ls' ) ]] bzw. * [[Vorlage(Befehl, 'find . -size +4k -ls' ) ]] sucht Dateien größer (`>`) 4kiB, also ab 4097 Byte. * [[Vorlage(Befehl, 'find . ! -size +4k -ls' ) ]] sucht Dateien bis maximal (`≤`) 4kiB. Der Operator `!` wird [#Kombinationen unten] erklärt. Man schreibe also numerische Angaben niemals ohne Multiplikator und immer * entweder mit beliebigem Vorzeichen und mit Multiplikator `c` * oder mit dem Vorzeichen `+` und beliebigem Multiplikator. == Alter == Die Tests `-Xtime`, `Xmin`, `-newer`, `-Xnewer` sowie `-newerXt` und `-newerXY` (mit X, Y ∈ { a, c, m }) vergleichen einen Zeitstempel der untersuchten Datei mit dem aktuellen Zeitpunkt, Mitternacht oder einem Zeitstempel einer Referenzdatei. An der Stelle `X` ist der Kennbuchstabe des zu untersuchenden Zeitstempels einzusetzen: * `m` für mtime (''modification time''), d.h. Zeitpunkt der letzten Änderung des Dateiinhalts. * `c` für ctime (''changed time''), d.h. Zeitpunkt der letzten Änderung der Verwaltungsdaten der Datei, dazu gehören Dateiname, Größe, Besitzer, Dateiberechtigungen, Zeitstempel und ähnliche Daten. * `a` für atime (''access time'', Zugriff), d.h. Zeitpunkt des letzten Lesens des Dateiinhalts. Eine Dateiauflistung selbst ist damit nicht gemeint. Bei Bilddateien z.B. zählt aber die Vorschaufunktion eines grafischen Dateimanagers oder das Auslesen der Bildeigenschaften bereits als Zugriff. Die Zugriffszeit wird in der Regel erst bei mehr als 24 h Abweichung oder wenn sie älter als die letzte Änderung der Datei ist, also nicht bei jedem Lesen, aktualisiert (wenn das Dateisystem nicht mit vom Standard abweichenden zusätzlichen Optionen eingebunden ist). Man kann auch bei der Einbindung vorgeben, dass atime gar nicht gepflegt wird und dann kann der Test `-atime` von find falsche Ergebnisse liefern und der Test `-amin` wird sehr wahrscheinlich falsche Resultate liefern. Der Linux Kernel unterstützt vier Zeitstempel, das Programm find kann aber mit dem von POSIX nicht definiertem Zeitstempel btime (für ''birth'', Geburt, auch ''creation time'') nicht umgehen. Lediglich für die Tests `-newerXY` ist eine Unterstützung angedacht, aber in GNU find für Linux bisher nicht implementiert. Bei `-Xtime` und `-Xmin` gibt, ähnlich wie bei der [#Groesse Größe], das Vorzeichen des Vergleichswertes an, ob man auf älter (`+`), gleichaltrig oder jünger (`-`) prüfen will. Die Tests `-Xtime` verwenden als Maßeinheit immer Tag im Sinne einer Zeitspanne vor 24 Stunden, nicht im Sinne von Kalendertag, und die Tests `-Xmin` verwenden Minute. Wie bei den Test auf Größe gilt auch hier: [#Numerische-Angaben find rechnet seltsam] mit den Vergleichswerten. * [[Vorlage(Befehl, 'find . -mtime -100 -ls' ) ]] sucht nach Dateien, deren Inhalt innerhalb der letzten 2400 Stunden geändert wurde bzw. in diesem Sinne jünger als 100 Tage sind. * [[Vorlage(Befehl, 'find . -mtime 100 -ls' ) ]] sucht nach Dateien, die mindestens 2400 Stunden alt, aber jünger als 2024 Stunden sind. * [[Vorlage(Befehl, 'find . -mtime +100 -ls' ) ]] sucht nach Dateien, deren Inhalt vor mehr als 2424 Stunden geändert wurde bzw. in diesem Sinne älter als 100 Tage sind. Diese Befehle und auch ihre Pendants mit `atime` und `ctime` können den Bediener verwirren. In der Praxis justiert man mit `-daystart` den zeitlichen Bezugspunkt auf den Beginn (Mitternacht) des aktuellen Tages, arbeitet damit effektiv doch mit Kalendertagen und kann dann (und sollte nur!) solche Befehle verwenden: * [[Vorlage(Befehl, 'find . -daystart ! -mtime +0 -ls' ) ]] zeigt nur Dateien, die heute (=0) geändert wurden. * [[Vorlage(Befehl, 'find . -daystart ! -mtime +1 -ls' ) ]] zeigt nur Dateien, die gestern (=1) oder heute geändert wurden. * [[Vorlage(Befehl, 'find . -daystart ! -mtime +2 -ls' ) ]] zeigt nur Dateien, die vorgestern (=2), gestern oder heute geändert wurden. * [[Vorlage(Befehl, 'find . -daystart ! -mtime +N -ls' ) ]] zeigt nur Dateien, die in den zurückliegenden N Kalendertagen bis einschließlich heute geändert wurden. Die Tests`-Xmin` arbeiten mit zeitlicher Auflösung von Minuten: {{{#!vorlage Warnung Eine vor dem Test notierte Angabe `-daystart` wirkt auch unwiderruflich auf späteres `-Xmin`! }}} * [[Vorlage(Befehl, 'find . ! -cmin +60 -ls' ) ]] zeigt nur Dateien, die in der letzten Stunde verändert wurden. Dies betrifft auch inhaltliche Änderungen, denn eine Aktualisierung des Zeitstempels mtime ist eine Änderung in den Verwaltungsdaten, die eine Aktualisierung des Zeitstempels ctime erzwingt. * [[Vorlage(Befehl, 'find . ! -mmin +60 -ls' ) ]] zeigt nur Dateien, die in der letzten Stunde inhaltlich verändert wurden. * [[Vorlage(Befehl, 'find . ! -amin +60 -ls' ) ]] würde die Dateien anzeigen, die in der letzten Stunde inhaltlich gelesen wurden, sofern man im Dateisystem die minütliche Pflege des Zeitstempels atime aktiviert hätte und das auch bei der Einbindung berücksichtigt hätte. In der Regel trifft das aber nicht zu und manche Typen von Dateisystemen können atime gar nicht mit minütlicher Auflösung speichern. (Hinweis: Die Aussagekraft der Datei-Zugriffszeit ist stark von den [:mount/#Optionen:Einhängeoptionen] `atime`, `noatime` und `relatime` abhängig.) [[Anker( Tests-newer ) ]] Die Tests `-newer` und Varianten bieten eine mehr dem natürlichen Sprachgebrauch entsprechende Syntax und Semantik: * Im Vergleich zu einer bestimmten Datei [[Vorlage(Befehl, 'find . -cnewer /tmp/referenz' ) ]] sucht nach Dateien, deren Name oder Status nach der __Änderungszeit__ der Referenzdatei geändert wurden. Mit [[Vorlage(Befehl, "touch --date='2004-02-29 15:00' /tmp/referenz`" ) ]] erstellt man sich eine Referenzdatei, wenn man keine hat. * Der Test `-newer` beschränkt das auf inhaltliche Änderungen, macht also das, was man von einem Test `-mnewer` erwarten würde, den es aber unter diesem Namen nicht gibt. * Es gibt auch einen Test `-anewer` mit denselben Einschränkungen wie `-atime` und `-amin`. * `-newercc` ist ein alternativer Name für `-cnewer`, und `-newermm` ist ein alternativer Name für `-newer`. Man kann aber in `-newerXY` auch mit X ≠ Y unterschiedliche Arten von Zeitstempeln vergleichen. [[Anker( newerXt ) ]] Die Tests `-newerct` und `newermt` sind von praktischem Wert, da sie als Vergleichswert auch umgangssprachliche Formulierungen ermöglichen, beispielsweise: * [[Vorlage(Befehl, "find . -newerct '0000'" ) ]] findet alle ab Beginn des heutigen Tages geänderten Dateien. * [[Vorlage(Befehl, "find . -newerct '0000 1 day ago'" ) ]] findet alle gestern oder heute geänderten Dateien. * [[Vorlage(Befehl, "find . -newerct '12 hours ago'" ) ]] findet alle in den letzten 12 Stunden geänderten Dateien. Für den Vergleichswert ist alles zulässig, was auch [:date:] für seine Option „`-d`“ akzeptieren würde, in dieser Sprache ist `0000` eine Schreibweise für Mitternacht. == Sonstige Suchkriterien == Einige ausgewählte Beispiele: * Alle Dateien des Benutzers klaus: [[Vorlage(Befehl, "find / -user klaus" ) ]] Der Benutzer kann mit seinem Anmeldenamen oder als numerische Benutzerkennung UID angegeben werden. Da dieser Befehl die gesamte Dateihierarchie durchsucht, ist sinnvoll, ihn mit [:sudo:] zu verwenden. * Alle Dateien im eigenen persönliche Verzeichnis, die Fremden gehören: [[Vorlage(Befehl, "find ~ ! -user $USER -ls" ) ]] Diese Liste sollte leer sein. * Leere Verzeichnisse und Dateien: [[Vorlage(Befehl, 'find . -empty' ) ]] Leere reguläre Dateien haben die Größe 0 und können daher auch über `-size` gefunden werden, aber Ordner, auch leere, haben niemals die Größe 0, sondern belegen immer mindestens 1 Cluster (oft: 4kiB), der zur Speicherung der Namen der Dateien verwendet wird, die im Ordner liegen. Auch diese Liste ist niemals leer, sondern enthält immer die Namen „`.`“ und „`..`“. Für diesen Test gelten Ordner als leer, wenn sie nichts weiteres enthalten. * Verzeichnistiefe begrenzen: [[Vorlage(Befehl, 'find . -maxdepth 3' ) ]] steigt bei der Suche nur 3 Verzeichnisebenen herab. [[Vorlage(Befehl, 'find . -mindepth 1' ) ]] durchsucht die [#Startpunkte Startpunkte], liefert sie aber nicht als Treffer – hier das aktuelle Verzeichnis. [[Anker( find-rechnet-seltsam ) ]] = Numerische Angaben = {{{#!vorlage Experten (Dieses Kapitel kann man beim ersten Lesen überschlagen. Es enthält Hintergrundinformationen und Begründungen für praktische Regeln.) Numerische Angaben für find gehorchen nicht der naiven Erwartung! Für find bedeuten beispielsweise die Angaben `4096c` und `4k` __nicht__ dieselbe Größe, und die Angabe `4096` (ohne Multiplikator) selektiert per Vorgabe den Multiplikator `b` alias 512 Byte, und find versteht deshalb 4096 als 2 Mebibyte bzw. 2095104 Byte. Der von find verwendete Algorithmus berechnet zunächst aus der zu prüfenden Zahl (z.B. die Größe einer Datei) Z und dem Wert des geltenden Multiplikators M die Hilfswerte „`Z \ M`“ (ganze Zahl) und „`Z mod M`“. Anschließend wird ein Testwert V ermittelt: Wenn „`Z mod M = 0`“, also wenn „`Z / M`“ ganzzahlig wäre, dann wird „`V = Z \ M`“ gesetzt, und anderenfalls wird aufgerundet zu „`V = 1 + Z \ M`“. Der so ermittelte ganzzahlige Testwert `V` wird dann mit dem Absolutwert der ganzen Zahl aus dem Vergleichswert `N` verglichen. Bei der Suche nach Dateien kleiner als 4096 Byte ergeben sich beispielsweise die Rechenergebnisse lt. folgender Tabelle. ||<-9 rowclass="titel">Tabelle 3c?: Rechenbeispiele|| || Test||N||M||Z||Z \ M||Z mod M = 0||V||Vergleich||naive Erwartung|| ||`-size -4096c`||4096||c ≙ 1 ||4095||4095||<:>ja ||4095||4095 < 4096||<|3>erfüllt|| ||`-size -4096c`||4096||c ≙ 1 ||4096||4096||<:>ja ||4096||4096 < 4096|| ||`-size -4096c`||4096||c ≙ 1 ||4097||4097||<:>ja ||4097||4097 < 4096|| ||`-size -4096` ||4096||b ≙ 512||3584|| 7||<:>ja || 7||7 < 4096 ||<|2>zufällig erfüllt|| ||`-size -4096` ||4096||b ≙ 512||4095|| 7||<:>nein|| 8||8 < 4096 || ||`-size -4096` ||4096||b ≙ 512||4096|| 8||<:>ja || 8||8 < 4096 ||<|2>nicht erfüllt|| ||`-size -4096` ||4096||b ≙ 512||4097|| 8||<:>nein|| 9||8 < 4096 || ||`-size -4k` ||4096||k ≙ 1024||3072|| 3||<:> ja || 3||3 < 4 ||erfüllt|| ||`-size -4k` ||4096||k ≙ 1024||4095|| 3||<:>nein|| 4||4 < 4 ||nicht erfüllt|| ||`-size -4k` ||4096||k ≙ 1024||4096|| 4||<:> ja || 4||4 < 4 ||<|2>erfüllt|| ||`-size -4k` ||4096||k ≙ 1024||4097|| 4||<:>nein|| 5||5 < 4 || Auch bei Größentests auf „exakte“ Gleichheit (Vergleichswert ohne Vorzeichen) gibt es wegen der Blockarithmetik von find der naiven Erwartung ähnlich widersprechende Ergebnisse (hier nicht gezeigt). Lediglich bei Größentests auf „größer als“ entsprechen die Rechenkünste von find der naiven Erwartung. }}} Daraus ergeben sich für die Praxis folgende Ratschläge: * Vergleichsgrößen immer mit Multiplikator angeben. Wenn es Probleme mit der Suche nach Größe gibt, dann wahrscheinlich, weil man `c`, `k`, `M` oder `G` vergessen hast. * Nach Möglichkeit nur Tests auf „größer“ verwenden (Vergleichswert mit Vorzeichen „`+`“); eine Negation des Tests mit „`!`“ ergibt dann einen Test auf „kleiner oder gleich“. * Wenn man Vergleichswerte ohne Vorzeichen oder mit dem Vorzeichen „`-`“ verwenden will, verwende man als Multiplikator `c`. Vorstehende Ausführungen und Regeln für die Praxis gelten neben den Tests auf [#Groesse Größe] auch für alle weiteren, die eine numerische Angabe erwarten, insbesondere bei den Tests auf [#Alter Alter]. Auch hier bevorzuge man Tests auf „später als“, angegeben durch das Vorzeichen „`+`“ oder Namensbestandteil `newer`. = Kombinationen = Die Gesamtheit aller [#Tests Tests] und [#Aktionen Aktionen] bildet den in der [#RTFM Dokumentation] so genannten ''Ausdruck (expression)'', in dem standardmäßig der Operator „Und“ die einzelnen Komponenten miteinander verbindet. Möglich sind aber auch andere Operatoren gemäß folgender Tabelle. {{{#!vorlage Tabelle <-2 rowclass="titel">Tabelle 4: Operatoren +++ Operator Beschreibung +++ (Leerraum) Durch Leerraum verbundene Tests bzw. Aktionen werden mit `-a` verbunden. +++ '''`-a`'''[[BR]]`-and` Konjunktion („Und“): Beide Tests müssen bestanden werden, oder der Dateiname gehört nicht mehr zum Arbeitsergebnis. +++ '''`-o`'''[[BR]]``-or``[[BR]] Disjunktion („Oder“): Die Datei muss mindestens einen, darf aber auch beide Tests bestehen, oder ihr Dateiname wird aus dem Arbeitsergebnis entfernt. +++ `-not`[[BR]]'''`!`''' Negation: Der Dateiname wird aus dem Arbeitsergebnis entfernt, wenn die Datei den Test besteht. +++ ``,`` Listenbearbeitung: In Konstrukten wie z.B. „`A , B , C`“ werden die Komponenten sequenziell und einzeln bearbeitet, und die Arbeitsergebnisse außer dem letzten (also im Beispiel das von `C`) werden verworfen. }}} (In der Tabelle sind die Schreibweisen nach POSIX fett dargestellt, die anderen sind in der GNU-Variante von find Synonyme dazu.) Die übliche Rangfolge der Operatoren wird beachtet: Negation bindet stärker als Und; Und bindet stärker als Oder. Wenn man etwas anderes will, muss man selber Klammern `()` verwenden, diese sind als Sonderzeichen der Shell bei ihrer Verwendung im Ausdruck für find immer zu quotieren oder zu maskieren. * Standard: Und-Kombination; die Funde müssen alle Kriterien erfüllen [[Vorlage(Befehl, 'find . -mindepth 3 -maxdepth 5' ) ]] sucht von Verzeichnistiefe 3 bis 5. * Weiteres Beispiel der Und-Kombination [[Vorlage(Befehl, 'find . -mindepth 3 -type f -name "*.avi" -size +5M' ) ]] beginnt die Suche in Verzeichnistiefe 3 und findet nur reguläre Dateien, die die Endung `.avi` haben und größer als 5 MiB sind. Man kann die Suchoptionen aber auch per Oder verknüpfen oder die Negation eines Tests bilden: * Negation: [[Vorlage(Befehl, 'find . ! -name "*.avi" -not -name "*.mp*g"' ) ]] sucht Dateien die weder die Dateiendung `avi` noch `mpg` oder `mpeg` haben. Das Ausrufezeichen und `-not` sind gleichbedeutend. * Oder-Kombination [[Vorlage(Befehl, 'find . -name "susi.*" -or -name "susanne.*"' ) ]] sucht Dateien die mit `susi.` ober `susanne.` beginnen. Bei umfangreichen Kombinationen kann eine Klammerung erforderlich sein, um das gewünschte Resultat zu erhalten: * Ohne Klammern wird in [[Vorlage(Befehl, 'find . -name "susi.*" -or -name "susanne.*" -name "*.txt"' ) ]] erst die Verbindung mit UND gebildet, also `susanne.*` und `*.txt`, danach erst ODER mit `susi.*`. Auch '''susi.png''' würde also gefunden. * Mit Klammern wird jetzt in [[Vorlage(Befehl, 'find . \( -name "susi.*" -or -name "susanne.*" \) -name "*.txt"' ) ]] für alle Dateien gefordert, dass diese auf `.txt` enden. Klammern müssen maskiert oder quotiert sowie mit Leerzeichen isoliert werden. Auch die Aktionen werden über Operatoren mit Tests verbunden, was manch überraschendes Ergebnis erzeugt. In einem Ordner mit diesen Dateien: {{{#!vorlage Befehl find . }}} {{{ . ./susanne.png ./susi.txt ./tusnelda.txt ./tusnelda.png ./susi.png ./susanne.txt }}} ergibt [[Vorlage(Befehl, "find . -name 'susi*' -o -name 'susan*' -print" ) ]] dieses Ergebnis: {{{ ./susanne.png ./susanne.txt }}} `susi` wurde also nicht gefunden, obwohl genau das beabsichtigt war. Erst wenn man sich erinnert, dass der Leerraum für „Und“ steht, sowie dass „Und“ stärker bindet als „Oder“, erkennt man die Übereinstimmung der Eingabe mit deren ausführlicheren Schreibweisen: {{{#!vorlage Befehl find . -name 'susi*' -o -name 'susan*' -print find . -name 'susi*' -o -name 'susan*' -a -print find . -name 'susi*' -o \( -name 'susan*' -a -print \) }}} bedeuten alle dasselbe: Dem Muster `susan*` entsprechende Dateinamen werden gesucht und ausgegeben; nach dem Muster `susi*` wird ebenfalls gesucht, aber die Funde werden nicht ausgegeben, weil ein automatisches `-print` nicht erfolgt wenn man selber eine Aktion wie `-print` angibt. = Aktionen = Auf ein vorläufiges oder auf das endgültige Suchergebnis kann man eine oder mehrere Aktionen nach folgender Tabelle anwenden; insbesondere kann man auch `-exec` mehrfach verwenden – meistens ist aber in solchen Situationen ein Skript zweckmäßiger. Auf das endgültige Suchergebnis wird automatisch `-print` angewendet, sofern man nicht eine eine Aktion aus folgender Tabelle angibt. {{{#!vorlage Tabelle <-2 rowclass="titel">Tabelle 5: Aktionen +++ Aktion Beschreibung +++ `-print` erzwingt die zeilenweise Ausgabe von Eigenname mit Pfad jeder gefunden Datei. +++ `-print0` gibt die Dateinamen wie `-print` aus, trennt diese aber durch ASCII NUL statt durch Zeilenvorschub (ASCII LF). +++ `-printf FORMAT` arbeitet wie `print`, wobei man das Ausgabeformat über FORMAT selber bestimmen kann. Die Möglichkeiten entsprechen weitgehend dem üblichen `printf` und sind in der [#RTFM Dokumentation] beschrieben. In der Regel wird FORMAT immer mit einem Zeilenende „`\n`“ beendet. +++ `-fprint DATEINAME`[[BR]]`-fprint0 DATEINAME`[[BR]]`-fprintf DATEINAME FORMAT`[[BR]]`-fls DATEINAME` arbeitet wie die entsprechende Aktion ohne führendes f, gibt die gefunden Dateinamen aber nicht auf die Standardausgabe (Bildschirm) aus, sondern schreibt diese in die als `DATEINAME` benannte Datei, die ggf. gelöscht oder neu angelegt wird. +++ `-ls` zeigt die Dateinamen der selektierten Dateien wie der Befehl `ls -dils`. +++ `-prune` verwirft das bisherige Arbeitsergebnis. +++ `-quit` beendet das Programm. Das kann sinnvoll sein, nachdem gefunden wurde, was gesucht wurde. +++ `-delete` löscht die gefundenen regulären Dateien und leere Verzeichnisse. +++ `-exec KOMMANDO ;` wendet auf jeden gefundenen Dateinamen einzeln `KOMMANDO` (= ein Programm mit optionalen Argumenten) an. Nach einem Argument `-exec` im [#Aufruf Aufruf] müssen noch mindestens 2 weitere Argumente folgen. Aus dem ersten und allen weiteren Argumenten, die nicht das Semikolon „`;`“ sind, wird ein Programmaufruf mit Name und Argumenten erstellt, dabei wird das spezielle Argument „`{}`“ von find durch den gefundenen Dateinamen (Eigenname mit Pfad) ersetzt. Das erste Semikolon beendet die Konstruktion des Programmaufrufs. Damit es nicht unbeabsichtigt von der aufrufenden Shell interpretiert wird, muss es immer quotiert oder maskiert werden. +++ `-exec KOMMANDO {} +` Wendet auf die Gesamtheit aller Funde einmalig `KOMMANDO` an. Es werden nach `-exec` noch mindestens 3 weitere Argumente benötigt, davon muss das letzte den Wert „`+`“ haben und der vorletzte den Wert „`{}`“ und diese müssen immer quotiert oder maskiert notiert werden, damit sie nicht von der aufrufenden Shell interpretiert werden. +++ `-ok …` Statt `-exec` kann man auch `-ok` mit derselben Syntax und Semantik für beide Aufrufformen verwenden, lediglich mit folgendem kleinen Unterschied: Mit `-ok` muss der Bediener vor der tatsächlichen Ausführung von KOMMAND den Aufruf bestätigen. +++ `-execdir …`[[BR]]`-okdir …` arbeiten weitgehend wie ihre Pendants ohne angehängtes `dir`, lediglich mit diesem Unterschied: Die Aktionen ohne angehängtem `dir` starten KOMMANDO in dem Arbeitsverzeichnis, in dem auch das aufgerufene Programm find aufgerufen wurde. `execdir` und `okdir` starten KOMMANDO in dem Ordner, welcher auch die gefundenen Dateien enthält. }}} == Dateien listen == * Ohne weitere Angaben gibt find nur die Namen der gefundenen Dateien mit Pfad aus: \\ [[Vorlage(Befehl, 'find /boot/grub/ -name "he*"' ) ]] {{{ /boot/grub/hexdump.mod /boot/grub/hello.mod /boot/grub/help.mod }}} * Wie bereits weiter oben erwähnt kann man mit `-ls` eine detailliertere Ausgabe erzeugen:\\ [[Vorlage(Befehl, 'find /boot/grub/ -name "he*" -ls' ) ]] {{{ 168624 4 -rw-r--r-- 1 root root 3196 Jan 13 17:08 /boot/grub/hexdump.mod 168603 4 -rw-r--r-- 1 root root 1308 Jan 13 17:08 /boot/grub/hello.mod 168623 4 -rw-r--r-- 1 root root 2200 Jan 13 17:08 /boot/grub/help.mod }}} * Wer die Ausgabe von find noch nach eigenen Vorstellungen gestalten möchte, verwende `-printf`. Man vergleiche die Ausgaben dieser beiden Befehle (:arrow: [#RTFM Dokumentation]): * [[Vorlage(Befehl, "find . -maxdepth 1 -type f -print" ) ]] * [[Vorlage(Befehl, "find . -maxdepth 1 -type f -printf '%P\\n'" ) ]] == Dateien löschen == Eine etwas kritische Angelegenheit ist das Löschen mit der Aktion `-delete`. {{{#!vorlage Warnung Da find auch Unterverzeichnisse durchsucht, sollte mit dieser Aktion vorsichtig umgegangen werden. Mit find gelöschte Dateien landen nicht im Papierkorb und können nicht wieder hergestellt werden. Man sollte `-delete` immer nur als letztes Wort des Aufrufs verwenden. }}} Der Verwendung sollte ein Test ohne `-delete` voraus gehen, um sicher zu gehen, nicht zu viele Dateien zu löschen. Für diesen Test ersetzt man in dem beabsichtigten Aufruf `-delete` durch `-print` und fügt die globale Option `-depth` hinzu: Aus dem beabsichtigten Befehl [[Vorlage(Befehl, 'find OPTIONen STARTPUNKTe TESTs AKTIONen -delete' ) ]] macht man also zunächst für den Test: \\ [[Vorlage(Befehl, 'find OPTIONen STARTPUNKTe -depth TESTs AKTIONen -print' ) ]] Gegenbeispiel: \\ Der folgende Aufruf löscht den kompletten Inhalt des Ordners '''/home/ottifant/''': {{{#!vorlage Befehl find /home/ottifant/ -delete -name Cache # falsch! }}} == Dateien bearbeiten == Mit `-exec` und dessen Varianten kann man ein beliebiges Programm oder auch ein ausführbares Skript auf jeden Fund anwenden: * Die Anzahl der Zeilen in Textdateien findet man mit `wc -l DATEI`; kombiniert mit find sieht das so aus: {{{#!vorlage Befehl find . -name "*.py" -exec wc -l {} \; }}}{{{ 10 ./abc.py 6 ./x/date-form.py 102 ./x/download.py }}} Das Kommando `wc -l` (Zeilen zählen) wird auf jede gefundene Datei angewendet. Die geschweiften Klammern werden durch die von `find` gefundenen Namen ersetzt. Das Ende der Programmaufrufs muss mit einem Semikolon angezeigt werden. Damit das Semikolon nicht von der Shell interpretiert wird, muss man es mit einem Backslash maskieren oder in Anführungszeichen setzen. * Als Parameter für `-exec` verschluckte Ausgabe von find wieder sichtbar machen {{{#!vorlage Befehl find tmp -name "a" -exec touch {} \; -print }}}{{{ ./tmp/a ./tmp/a/a ./tmp/a/a/a }}} Weil [:touch:] nichts ausgibt und man dann deshalb keine Kontrolle darüber hat, was getan wurde, erhält man diese so über die `-print`-Ausgabe von find. * Oft empfiehlt sich `-execdir` statt `-exec` {{{#!vorlage Befehl find . -type d -execdir tar -cjf archiv.tar.bz2 {} \; }}} `-execdir` führt das Kommando aus dem Verzeichnis heraus aus, in dem die Datei gefunden wird. So wird also für jedes Verzeichnis ein '''archiv.tar.bz2''' vor Ort angelegt. Mit einem einfachen `-exec` würde für jedes Verzeichnis ein Archiv im aktuellen Verzeichnis angelegt, d.h. das Archiv immer wieder überschrieben, so dass am Ende nur ein Archiv mit den Ergebnissen der letzten Ausführung von tar verbliebe. * Anstatt `-exec` bzw. `-execdir` kann man auch `-ok` bzw. `-okdir` verwenden {{{#!vorlage Befehl find -name "*pdf" -okdir xpdf {} \; }}} fragt vor jeder Datei nach, ob man wirklich die Aktion ausführen möchte. * Gesammelte Ausführung mit `+`\\ Beendet man ein Kommando mit Plus `+` statt mit Semikolon `;`, so werden mehrere, u.U. alle Funde auf einen Rutsch an das Kommando übergeben. Dies ist nur möglich, wenn das Kommando selbst mit mehreren Parametern zurechtkommt und das `+` unmittelbar den geschweiften Klammern folgt. Ein Beispiel mit [:du:] ergibt zunächst: {{{#!vorlage Befehl find . -name "*pdf" -exec du --total {} ";" }}} {{{ 16 ./A.pdf 16 insgesamt 12 ./B.pdf 12 insgesamt 100 ./C.pdf 100 insgesamt }}} Dagegen erhält man ein sinnvolleres Ergebnis mit `+`: {{{#!vorlage Befehl find . -name "*pdf" -exec du --total {} + }}} {{{ 16 ./A.pdf 12 ./B.pdf 100 ./C.pdf 128 insgesamt }}} Mit `-exec` & Co. kann man im Prinzip alles starten, was auch der Kernel starten könnte. Wenn man aber ein spezielles Sprachmittel einer Shell wie z.B. Befehlsverkettungen, Umleitungen, eingebaute Funktionen einsetzen möchte, wird das fehlschlagen. Man kann natürlich eine Shell wie die [:Bash:] per `exec` starten und dieser eine mehrfach quotierte Zeichenkette zur Ausführung übergeben – mehrfach quotiert, weil dieser Einzeiler vor der Interpretation durch die aufrufende Shell und durch find und durch die von find gestartete Shell geschützt werden muss, was Schwindel, Schädelweh, mentale Depressionen und dergl. fast sicher erzeugen wird. Besser sind diese Methoden: 1. Man erstellt ein Skript für die gewünschte Bearbeitung umd verwendet einen Aufruf wie: [[Vorlage(Befehl, 'find … -exec SKRIPT "{}" \;' ) ]] 1. oder wie: [[Vorlage(Befehl, 'find … -print | SKRIPT' ) ]] Statt eines Skripts kann es natürlich auch ein anderes ausführbares Programm sein; manchmal ist dafür auch [:xargs:] hilfreich. 1. oder man baut find in das Skript ein: {{{ # im Skript: find … -print | while read … do … done }}} = Beispiele = Es gibt eine Unzahl weiterer Beispiele, z.B. die Suche nach Eigentümer, Berechtigungen, Dateisystem u.v.m. Siehe hierzu die [#RTFM Dokumentation]. Das oben unter [#Aufruf Aufruf] genannte Beispiel {{{#!vorlage Befehl find -P ~ -xdev -type f -printf '%s\t%k\t%p\n' | sort -g -r | head -n 5 }}} funktioniert so: * Die [#Optionen (generelle) Option] `-P` kann man weglassen, da sie zum Standard gehört. Sie verhindert die Durchsuchung per [:ln:symbolischer Links] verknüpfter Ordner. Die [#Tabelle-3a globale Option] `-xdev` macht das ähnlich für die Einbindepunkte von anderen Dateisystemen. Beachte: Trotz vergleichbarer Semantik muss man die beiden Angaben syntaktisch unterschiedlich anwenden. * Die Tilde `~` wird von der aufrufenden Shell durch den Inhalt der [:Umgebungsvariable:] `HOME` ersetzt. * Die Aktion `-printf` erlaubt nicht nur die beliebige Formatierung der Funde, sondern beschafft über die mit dem Zeichen `%` eingeleiteten Format-Spezifikationen auch Eigenschaften der Datei (was der Aufruf von `printf` aus Programmiersprachen und das gleichnamige Programm nicht können); im Beispiel steht `%s` für die Größe in Bytes, `%k` für die belegte Größe in Kibibytes und `%p` für Dateinamen mit Pfad, weitere siehe [#RTFM Dokumentation]. Weiteres Beispiel: Der Befehl {{{#!vorlage Befehl sudo find / -xdev \( -path /home -prune , ! -uid -1000 \) -printf '%U\t%g\t%p\n' }}} ermittelt alle Dateien außerhalb der persönlichen Benutzerverzeichnisse, die normalen Benutzern (mit UID ab 1000) gehören, davon sollte es nur sehr wenige mit plausiblen Erklärungen geben. Funktionsweise: * Die Tests sollen hier nicht alle per Und verbunden werden, deshalb werden Klammern „`( … )`“ verwendet. Klammern haben auch für die aufrufende Shell eine besondere Bedeutung, die hier nicht gemeint ist; deshalb werden hier die Klammern vor einer Interpretation durch die aufrufende Shell geschützt. * Im Klammerausdruck verbindet der [#Kombinationen Operator] „`,`“ zwei Ausdrücke: * Der linke (`-path /home -and -prune`) sorgt dafür, dass dar Ordner '''/home''' nicht durchsucht wird. Das Arbeitsergebnis dieses Ausdrucks besteht nur aus dem Ordner '''/home''' selbst und wird verworfen. * Das Ergebnis des rechten Ausdrucks in der Klammer wird an die der schließenden Klammer folgenden Tests/Aktionen weiter gegeben und besteht aus allen Dateien, die „nicht Benutzern mit UIDs kleiner als 1000 gehören“. * Solche Konstrukte wie das hier beispielhaft gezeigte sind idiomatisch bei Verwendung der Aktion `prune`. * Zu „Test“ (eigentlich globale Option) `-xdev` und Aktion `-printf` siehe vorstehendes Beispiel. Beispielausgabe (gekürzt und teilweise zensiert): {{{ 1000 ░░░░░ /var/lib/samba/usershares/videos 1000 whoopsie /var/crash/_usr_bin_wireplumber.1000.crash 1000 ░░░░░ /var/log/installer/ubuntu_bootstrap.log.3376 1000 ░░░░░ /var/log/installer/ubuntu_bootstrap.log 1000 ░░░░░ /tmp/.X11-unix/X0 }}} * Dateien im Ordner '''/var/lib/samba/usershares/''' entstehen durch persönliche Freigaben von Ordnern durch normale Benutzer im jeweiligen Homeverzeichnis. [:Samba:] erstellt an Hand dieser Dateien automatische Freigaben. * Dateien im Ordner '''/var/crash/''' dokumentieren Systemabstürze und aus diesen automatisch generierte Fehlermeldungen an die Entwickler. * Im Ordner '''/tmp/''' darf jeder Dateien ablegen und das System darf diese jederzeit löschen. * Unterordner von '''/var/mail/''' können E-Mails des jeweiligen Benutzers enthalten. Über alle anderen Fälle sollte der verantwortungsbewusste Systemverwalter nachdenken und, wenn keine plausible Erklärung gefunden werden kann, auch entschlossen seiner Verantwortung entsprechend handeln – denn in solchen Fällen stimmt etwas nicht mit dem System. = Problembehebung = == find läuft endlos == Wenn man find eine umfangreiche Aufgabe gibt, z.B. großer Suchbaum, komplizierte Tests, ungeschickte Formulierung von Aktionen mit zu vielen Subprozessen, dann kann das Programm sehr lange laufen, möglicherweise auch mehrere Stunden. Der Eindruck, es würde niemals mehr zum Ende finden, ist jedoch nicht berechtigt. Selbst wenn man im Suchbaum mit symbolischen Links Schleifen erstellt hat, wird find diese erkennen und nur einmal durchlaufen. Wer die Geduld verliert, kann die Suche mit der Taste [[Vorlage(Tasten,Strg+c)]] abbrechen. == Fehlermeldungen == Gelegentlich verweigert find mit einer Fehlermeldung die Ausführung. Die in der Praxis am häufigsten erscheinende Fehlermeldung erhält man durch fehlerhafte Verwendung von Mustern. Beispiel: {{{#!vorlage Befehl find $HOME -name .* }}} {{{ find: Pfade müssen dem Ausdruck `.bash_history' vorangestellt werden find: mögliches nicht zitiertes Muster nach Aussage '-name'? }}} Statt '''.bash_history''' kann auch ein beliebiger anderer Dateiname genannt werden, das ist halt der zufällig erste, den die aufrufende Shell bei der Auswertung des Globs gefunden hat. Das ist auch schon der Bedienfehler: Es wurde nicht verhindert, dass die aufrufende Shell den [:Shell/Glob:Glob] auswertet. Korrekt ist: {{{#!vorlage Befehl find $HOME -name ".*" }}} (Die Formulierung „nicht zitiertes Muster“ ist eine schlechte Übersetzung von "unquoted pattern"; besser wäre hier „ungeschütztes Muster“.) == Warnungen == {{{#!vorlage Warnung Warnungen sind tückischer als Fehlermeldungen, weil man die zuerst ausgegebenen Warnungen wegen der dann folgenden (vermutlich fehlerhaften) Ausgabe leicht übersehen kann und dann mit dem falschen Ergebnis weiterarbeitet. }}} In der [#RTFM Dokumentation] wird beim [#Aufruf Aufruf] alles nach den Startpunkten als `AUSDRUCK` benannt. Dieser kann [#Tabelle-3a globale Optionen] (nicht zu verwechseln mit den generellen [#Optionen Optionen]), [#Tabelle-3b positionelle Optionen], [#Tests Tests], [#Kombinationen Operatoren] und [#Aktionen Aktionen] beinhalten. Stehen globale Optionen, die immer für die ganze Suche gelten, nicht am Anfang des Ausdrucks, so sieht das aus, als habe der Nutzer eine andere Absicht gehabt, und man bekommt deshalb eine Warnung. Beispiel: Der Befehl [[Vorlage(Befehl, 'find . -maxdepth 4 -name foo -or -maxdepth 2' ) ]] ergibt eine Warnung {{{ find: Warnung: Sie haben die globale Option -maxdepth nach dem Argument -name angegeben, aber globale Optionen sind nicht positionell, d.h. -maxdepth wirkt sich sowohl auf die davor als auch auf die danach angegebenen Tests aus. Bitte geben Sie globale Optionen vor anderen Argumenten an. }}} aus und anschließend eine Liste von Dateinamen, die aber vermutlich nicht der (mit find nicht realisierbaren) Vorstellung des Bedieners entspricht. Im Beispiel war wohl die Absicht des Bedieners: „Suche bis zu 4 Stufen tief nach `foo` und gebe das aus, oder, wenn es nicht gefunden wird, suche nut 2 Stufen tief und gebe das aus.“ Ein solche Anweisung kann find nicht erfüllen, denn wenn `foo` nicht gefunden wird, hat es ja schon 4 Stufen durchsucht anstatt der dann verlangten 2. Daraus ergibt sich die Regel für die Praxis: * Eine Angabe `-maxdepth` ist nur einmal im `Ausdruck` sinnvoll und man schreibt diese Angabe am besten als erstes in den Ausdruck. Das gilt entsprechend auch für `-mindepth`. = Links = * [:Shell/Befehlsübersicht:] {Übersicht} * [http://www.gnu.org/software/findutils/manual/html_mono/find.html findutils auf gnu.org] {en} – Sehr ausführliche Seite zum Thema Suche # tag: Shell, System