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 -exec
Parameter verwenden soll. Meine Frage ist daher: Woher weiß ich, wann ich eine Pipe verwenden |
und wann ich -exec
einen 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 -exec
so viele cp
Befehle 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 -exec
Dateinamen/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 -0
oder --null
) zu trennen. Und find
es 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 cpio
stattdessen, 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.