Find/Aktionen

Aus Foxwiki

Aktionen

-ls

zeigt das Verzeichnis in dem die getestete Datei gefunden wurde mit ls -dils an

-delete

Löscht die gefundenen Dateien

Achtung

Da find auch Unterverzeichnisse durchsucht, sollte mit dieser Option vorsichtig umgegangen werden

  • Mit find gelöschte Dateien landen nicht im Papierkorb und können nicht wieder hergestellt werden
  • Siehe auch Die Aktion -delete steht an der falschen Stelle
  • Vor der Verwendung sollte ein Test ohne -delete voraus gehen, um sicher zu gehen, nicht zu viele Dateien zu löschen
  • Die -delete-Option impliziert -depth, das heißt, man muss zum Testen auch -depth setzen, um keine Überraschung zu erleben
  • Es ist auch sorgfältig darauf zu achten, an welcher Position -delete steht. find test/ -name "c*" -delete
  • Löscht im Verzeichnis test und dessen Unterverzeichnissen alle Dateien, die mit "c" beginnen
  • Der Befehl löscht auch Verzeichnisse selbst, die mit "c" beginnen, diese jedoch nur, wenn sie leer sind, wie allgemein üblich bei Linux
  • Das ist der Grund, weshalb -delete ein -depth impliziert:
  • Wenn erst in den Unterverzeichnissen gelöscht wird kann ein leeres Oberverzeichnis auch gelöscht werden, umgekehrt nicht
Kombination mit anderen Kommandos

Now that you've found the files you're looking for, what are you going to do with them?

  • You can use find in conjunction with xargs or the -exec option to manipulate files after you've found what you're looking for
  • Say you want to change the ownership of a bunch of files from root to www-data
  • Finding all the files is only the first step; you also need to change the ownership
  • Doing it manually from a list of files returned by find sounds like tedium, and it is
  • So you might want to use the -exec option to change the ownership:
find -user root -exec chown www-data {} \;
  • That command tells find to pass all the files it finds to the chown utility and change the ownership to www-data
  • Piece of cake
Dateien bearbeiten

Schließlich wünscht man sich, mit der gefundenen Datei etwas anstellen zu können, das heißt, die gefundene Datei durch ein Kommando zu schleusen

  • Mit der Option -exec Kommando(s) {} ; wird in jedem Schritt die gefundene Datei der Reihe nach mit den angegebenen Kommandos bearbeitet
  • Die geschweiften Klammern dienen dabei als Platzhalter, der den aktuellen Dateinamen enthält
  • Das Semikolon schließt die exec-Option ab:
Suche nach leeren Dateien und zeige diese mittels "ls -l" an $ find ./bsp/ -empty -exec ls -l \{\} \;
insgesamt 0 insgesamt 0
-rw-r--r-- 1 user users 0 Jun 16 09:30 ./bsp/lib/bla/file
-rw-r--r-- 1 user users 0 Jun 16 09:30 ./bsp/lib/foo/file
Bemerkung* Die Maskierung der geschweiften Klammern und des Semikolons ist entscheidend, da diese sonst von der Shell substituiert werden (ein Semikolon wird bspw
  • entfernt)
  • Auch muss zwischen schließender Klammer und Semikolon ein Leerzeichen stehen!
-exec Kommando {} \;

Wendet auf alle gefundenen Dateien den Shellbefehl "Kommando" an. {} steht dabei als Platzhalter für die gefundenen Dateinamen

  • Das Zeichen ; terminiert den von find aufzurufenden Shellbefehl, damit es nicht unbeabsichtigt von der Shell interpretiert wird muss es mit \ maskiert werden
-exec Kommando; <<

führt das Kommando aus; die Aktion ist wahr, wenn das Kommando einen Status von Null liefert; alle auf den Kommandonamen folgenden Argumente bis zu einem Semikolon

  • werden als Kommandozeilenargumente für das Kommando interpretiert
  • das Semikolon kann nicht weggelassen werden, und es muss durch mindestens ein Whitespace von der letzten Option getrennt werden
  • die Konstruktion {} wird durch den Pfadnamen der Datei ersetzt; die Klammern und das Semikolon müssen in der Kommandozeile für find quotiert werden, damit sie nicht von der Shell bearbeitet werden
Using ‑exec Efficiently

The ‑exec action takes a command (along with its options) as an argument

  • The arguments should contain {} (usually quoted), which is replaced in the command with the name of the currently found file
  • The command is terminated by a semicolon, which must be quoted (“escaped”) so the shell will pass it literally to the find command
  • To use a more complex action with ‑exec, you can use “complex-command” as the Unix command
  • Here's a somewhat contrived example, that for each found file replaces “Mr.” with “Mr
  • or Ms.”, and also converts the file to uppercase: find whatever... -exec sh -c 'sed "s/Mr\./Mr
  • or Ms./g" "{}" \' | tr "[:lower:]" "[:upper:]" >"{}.new"' \;
  • The ‑exec action in find is very useful. But since it runs the command listed for every found file, it isn't very efficient
  • On a large system this makes a difference! One solution is to combine find with xargs as discussed above: find whatever... | xargs command
  • However this approach has two limitations. Firstly not all commands accept the list of files at the end of the command. A good example is cp: find . -name \*.txt | xargs cp /tmp # This won't work!</nowiki>

(Note the Gnu version of cp has a non-POSIX option “‑t” for this, and Gnu xargs has options to handle this too.)

  • Secondly, filenames may contain spaces or newlines, which would confuse the command used with xargs. (Again Gnu tools have options for that, “find ... ‑print0 | xargs ‑0 ...”.)
  • There are standard POSIX (but non-obvious) solutions to both problems
  • An alternate form of ‑exec ends with a plus-sign, not a semi-colon. This form collects the filenames into groups or sets, and runs the command once per set
  • This is exactly what xargs does, to prevent argument lists from becoming too long for the system to handle
  • In this form, the {} argument expands to the set of filenames
  • For example:
find / -name core -exec /bin/rm -f '{}' +
-execdir Kommando {} +

Wendet auf alle gefundenen Dateien den Shellbefehl "Kommando" an

  • Im Ggs
  • zu -exec wird das Kommando im Verzeichnis, in dem die Datei liegt, ausgeführt
  • Das Plus statt des \; am Ende provoziert die parallele Ausführung der Kommandos, und kann auch bei -exec verwendet werden
Mehrere Kommandos ausführen

As for the find command, you can also just add more -exec commands in a row:

$ find . -name "*" -exec chgrp -v new_group '{}' \; -exec chmod -v 770 '{}' \;
  • Note that this command is, in its result, equivalent of using chgrp -v new_group file && chmod -v 770 file on each file
  • All the find's parameters such as -name, -exec, -size and so on, are actually tests: find will continue to run them one by one as long as the entire chain so far has evaluated to true
  • So each consecutive -exec command is executed only if the previous ones returned true (i.e. 0 exit status of the commands)
  • But find also understands logic operators such as or (-o) and not (!)
  • Therefore, to use a chain of -exec tests regardless of the previous results, one would need to use something like this:
$ find . -name "*" \( -exec chgrp -v new_group {} \; -o -exec chmod -v 770 {} \; \)

@user Unfortunately, I don't know if it is still necessary

  • I did some test just now and haven't come across a situation where it would change anything
  • I guess it's just "good practice" that will die out. – rozcietrzewiacz Aug 5 '11 at 8:04
$ find . -name "*" -exec sh -c 'chgrp -v new_group "$0" ; chmod -v 770 "$0"' {} \;

@Gilles: The wonders of -c's odd handling of $0 make me think this is wrong every time I glance at it, but its definitely correct – derobert Aug 24 '12 at 16:52

-ok

Anstatt -exec kann man auch -ok verwenden

  • Hierbei wird jedes mal gefragt, ob man die Aktion ausführen möchte
  • Meist empfiehlt sich -execdir statt -exec find test -type d -exec tar -cjf archiv.bz2 {} \;

-execdir führt das Kommando aus dem Verzeichnis heraus aus, in dem die Datei gefunden wird

  • So wird also für jedes Unterverzeichnis ein archiv.bz2 vor Ort angelegt
  • Mit einem einfachen -exec würde für jedes Verzeichnis ein Archiv im aktuellen Verzeichnis angelegt, das heißt, das Archiv immer wieder überschrieben, so dass am Ende nur ein Archiv mit den Ergebnissen des letzten Verzeichnisses existiert
-ok Kommando;

wie -exec, vor der Ausführung des Kommandos wird aber noch eine Bestätigung erwartet; nur eine Eingabe, die mit einem B oder einem y beginnt, führt zur Ausführung des Kommandos

-ok Kommando {} \;

Wie -exec, allerdings wird vor jeder Aktion eine Bestätigung erfragt. {} steht dabei als Platzhalter für die gefundenen Dateinamen

-okdir
find -name "*pdf" -okdir xpdf {} \;

-okdir fragt im Gegensatz zu -execdir vor jeder Datei nach, ob man wirklich die Aktion ausführen möchte

Parallele Ausführung mit +
find -name "*pdf" -execdir md5sum {} +
  • Beendet man ein Kommando mit Plus + statt mit Semikolon ;</nowiki>, so werden mehrere, gegebenenfalls alle Funde auf einen Rutsch an das Kommando übergeben
  • Dies ist dann sinnvoll, wenn das Kommando selbst mit mehreren Parametern zurechtkommt
  • Beispiele: find test -type f -execdir md5sum {} ";"
  • ergibt: md5sum a md5sum b md5sum c
  • Dagegen ergibt: find test -type f -execdir md5sum {} + md5sum a b c
  • Das + kann nur verwendet werden, wenn die geschweiften Klammern unmittelbar davor stehen
  • Eine etwas heikle Angelegenheit ist das Löschen mit der Option -delete
-okdir Kommando {} +

Wie eine Kombination von -ok und -execdir, das heißt, es wird eine Bestätigung erfragt, und das Kommando wird im Fundordner ausgeführt

  • Das Plus kann statt ";" verwendet werden, wenn die {} der letzte Parameter sind; dann werden mehrere Funde auf einmal an Kommando übergeben

Siehe auch

{{Special:PrefixIndex/Vorlage:Find}}