Kombinieren von „find“ mit anderen Befehlen: Wann wird „-exec“ und wann „pipe“ verwendet?

Kombinieren von „find“ mit anderen Befehlen: Wann wird „-exec“ und wann „pipe“ verwendet?

Ich habe gelernt, den Befehl „Find“ allein zum Suchen von Dateien und Verzeichnissen zu verwenden. Wenn es jedoch darum geht, etwas mit den Dateien/Ordnern zu tun, bin ich verwirrt.

Gegeben sei der folgende Befehl:

find . -type f -iname "*.cr2" 

Wenn ich die oben gefundenen Dateien in ein neues Verzeichnis kopieren möchte, würde ich natürlich an die Verwendung von copy ( cp) und pipe denken |.

find . -type f -iname "*.cr2" | cp \destination_directory

Und für mich bedeutet dies, dass alle meine Fotos auf einem ganzen Laufwerk und in mehreren Unterordnerebenen verschachtelt in einem einzigen Ordner landen und ich mit der Organisation beginnen kann.

Allerdings wird mir immer wieder gesagt, dass ich den -execParameter verwenden soll. Meine Frage ist daher: Woher weiß ich, wann ich eine Pipe verwenden |und wann ich -execeinen Befehl wie unten verwenden soll?

 find . -name "*.pdf" -type f -exec cp {} ./pdfsfolder \;

BEARBEITEN

Die vorgeschlagene Lösung (unten) kopiert nur Dateien, deren Dateinamen eindeutig sind. Außerdem heißt es, dass cp file.txt nicht kopiert und durch file.txt ersetzt. Wenn Sie viele Dateien kopieren und nicht wissen, ob es Dateien mit demselben Namen gibt, wie kopieren Sie dann etwas und benennen es beispielsweise um, wenn der Dateiname vorhanden ist?

Vorgeschlagene Lösung

find . -type f -iname "*.txt" -print0 | xargs -0 cp -t /home/josh/Documents/copy/

/home/josh/documents/copy ist das Verzeichnis, in das ich Sachen verschieben möchte.

Antwort1

Ihre Annahmen enthalten Fehler, doch zunächst einige Hintergrundinformationen:

Sie sollten zwischen zwei Verwendungsmöglichkeiten von unterscheiden -exec:

  • mit \;dem {} wird durch ein einzelnes gefundenes Element ersetzt
  • wobei durch viele Elemente ersetzt wird (so viele, wie die Befehlszeile aufnehmen kann) +.{}

Daher ruft Ihr Anwendungsbeispiel -execso viele cpBefehle auf, wie Elemente gefunden werden find.

Die Verwendung find ... -exec cmd {} ... +ist hinsichtlich der Effizienz ähnlich wie die Weiterleitung der Ausgabe von „find“ an einen Befehl, der mehrere Eingabenamen verarbeitet.

Sie sollten auch berücksichtigen, dass -execDateinamen/Pfade mit Leerzeichen zwar gut verarbeitet werden, dies jedoch Probleme verursachen kann, wenn Sie die Ausgabe von find an ein anderes Programm weiterleiten. Daher kann einigen Programmen, die eine Liste von Dateinamen von stdin erwarten, die Option gegeben werden, diese Dateinamen durch NUL (oft -0oder --null) zu trennen. Und findes gibt eine Option, sie auf diese Weise an das nächste Programm weiterzugeben, indem Folgendes angegeben wird:-print0


Kommen wir nun zu Ihren Beispielen:

find . -type f -iname "*.cr2" | cp destination_directory

kopiert die gefundenen Dateien nicht, da cp nicht von der Standardeingabe liest. Sie müssten verwenden:

find . -type f -iname "*.cr2" | xargs cp -t destination_directory

oder um die Pfade mit Leerzeichen zu behandeln:

find . -type f -iname "*.cr2" -print0 | xargs -0 cp -t destination_directory

Mit ungefähr der gleichen Effizienz könnten Sie Folgendes tun:

find . -type f -iname "*.cr2" -exec cp -t destination_directory {} +

(Wie G-Man betonte, {}muss das am Ende stehen, vor dem +) Alle oben genanntennichtErstellen Sie dazu die Hierarchie unter dem Zielverzeichnis. Aus alter Gewohnheit verwende ich cpiostattdessen, auch wenn das Quellverzeichnis flach ist:

find . -type f -iname "*.cr2" -print0 | cpio -pdmv0 destination_directory

in dem schön aufgelistet ist, was es unterwegs tut.


Die relevanten Teile von man find:

-exec command ;
       Execute command; true if 0 status is returned.   All  following
       arguments  to  find  are  taken  to be arguments to the command
       until an argument consisting of `;' is encountered.  The string
       `{}'  is  replaced  by  the  current  file name being processed
       everywhere it occurs in the arguments to the command, not  just
       in  arguments  where  it is alone, as in some versions of find.
       Both of these constructions might need to be  escaped  (with  a
       `\')  or  quoted  to  protect them from expansion by the shell.
       See the EXAMPLES section for examples of the use of  the  -exec
       option.   The  specified  command  is run once for each matched
       file.  The command  is  executed  in  the  starting  directory.
       There  are unavoidable security problems surrounding use of the
       -exec action; you should use the -execdir option instead.

-exec command {} +
       This variant of the -exec action runs the specified command  on
       the  selected files, but the command line is built by appending
       each selected file name at the end; the total number of invoca‐
       tions  of  the  command  will  be  much less than the number of
       matched files.  The command line is built in much the same  way
       that xargs builds its command lines.  Only one instance of `{}'
       is allowed within the command.  The command is executed in  the
       starting directory.

verwandte Informationen