Wie lasse ich den Befehl 'cp' keinen Fehler auslösen, wenn die Quelldatei nicht existiert?

59

Ich benutze Mac OS X. Ich versuche, einige Dateien mit dem Befehl cp für ein solches Build-Skript zu kopieren.

cp ./src/*/*.h ./aaa

Dieser Befehl löst jedoch einen Fehler aus, wenn sich keine .h-Datei im Verzeichnis ./src befindet. Wie mache ich den Befehl, um den Fehler nicht auszulösen? (Stiller Fehler) Der Fehler führt zum Fehlschlagen des Build-Ergebnisses, aber ich möchte nur kopieren, wenn nur eine Header-Datei vorhanden ist.

Eonil
quelle

Antworten:

69

Wenn Sie über die Fehlermeldung sprechen, können Sie dies unterdrücken, indem Sie sie an den Bit-Bucket senden:

cp ./src/*/*.h ./aaa 2>/dev/null

Wenn Sie den Exit-Code und die Fehlermeldung unterdrücken möchten:

cp ./src/*/*.h ./aaa 2>/dev/null || :
Dennis Williamson
quelle
8
Es wäre schön zu erklären, was :in diesem Zusammenhang bedeutet.
Piotr Dobrogost
23
@PiotrDobrogost: In Bash und einigen anderen Shells ist der Doppelpunkt ein Null-Dienstprogramm (no-op). Es wird angegeben durch POSIX . Da es immer true zurückgibt, wird es hier verwendet, um den Exit-Code eines fehlgeschlagenen zu unterdrücken cp(falls gewünscht). Die eingebaute Shell truekönnte stattdessen verwendet werden und wäre besser lesbar.
Dennis Williamson
1
Dabei werden auch andere Fehler ignoriert (Quell- / Zielverzeichnis existiert nicht, Quelldatei existiert, ist aber nicht lesbar, Festplatte voll, schreibgeschütztes Dateisystem, E / A-Fehler, cpnicht in PATHirgendeiner Form vorhanden ...)
Vladimir Panteleev
Syntaxfehler in der Nähe des unerwarteten Tokens "||"
thang
13

Sie suchen nach etwas in der Art von

if [ -e file ]
 then cp file /somewhere
fi

(Leider ist die -fOption nicht der Droide, den Sie suchen.)

Wenn Sie einen Glob abgleichen möchten, funktioniert das nicht. Verwenden Sie findstattdessen zB:

find ./src -name \*.h -exec cp {} ./destination \;
Brad Ackerman
quelle
Beachten Sie, dass es bei einem solchen Ansatz ein potenzielles TOCTOU-Problem gibt (wenn Sie z. B. verwenden set -eund die Datei zwischen dem [und den cpAufrufen verschwindet , stürzt Ihr Skript ab).
Vladimir Panteleev
9

Alte Frage, könnte aber für andere noch relevant sein.
Wenn Sie cp nicht benötigen , können Sie es mit rsync versuchen.
Führen Sie Folgendes aus, um alle Dateien von einer Quelle in ein Zielverzeichnis zu kopieren:

rsync -avzh --ignore-errors /path/to/source /path/to/destination

Rsync wird mit den meisten Unix-ähnlichen Systemen wie Linux, Mac OS X oder FreeBSD geliefert.

mre
quelle
4
Sie könnten rsync anstelle von cp verwenden und den Parameter hinzufügen --ignore-missing-args: rsync -av --ignore-missing-args ./src/*/*.h ./aaaDies hat den Vorteil, --ignore-errorsdass die einzigen Fehler ignoriert werden, die sich auf nicht vorhandene Quelldateien beziehen. Bei --ignore-errorsjedem Fehler wird ignoriert, was gefährlich sein kann. Berücksichtigen Sie außerdem, dass dieser Parameter relativ neu ist, sodass er in alten Versionen von rsync möglicherweise nicht vorhanden ist.
Jesjimher
6

Wenn Sie das Ergebnis auf true setzen, wird sichergestellt, dass der Befehl immer erfolgreich ausgeführt wird. Ich habe es unter Linux versucht, aber unter keinem Mac OS:

cp ./src/*/*.h ./aaa | true
Vivek
quelle
5
Die einfache Pipe |wird immer ausgeführt, solange ||dies nur im Fehlerfall erfolgt. Und trueist normalerweise eine Binärdatei, während der Doppelpunkt :eine eingebaute ist und keine PID verbraucht.
ott--
Ein Bash-Skript unter MacOS-Yosemite mit dem Befehl "cp ./src/*/*.h ./aaa" führt keinen Fehler aus, wenn die .h-Dateien nicht vorhanden sind.
Vivek
2

Sie können den korrekten Fehlerstatus erzwingen. Mit einer Funktion:

$ cpalways () { cp $1 $2 2>/dev/null ; return 0 ; }

Angesichts der folgenden:

$ ls foo bar baz
ls: baz: No such file or directory
bar foo

Beim normalen Kopieren wird ein Fehler zurückgegeben. Es wird ein Exit-Status von 1 zurückgegeben.

$ cp baz bar ; echo $?
cp: baz: No such file or directory
1

Wenn wir die obige Funktion cpalways () verwenden, werden alle Fehler ausgeblendet:

$ cpalways baz bar ; echo $?
0
$ cpalways foo bar ; echo $?
0
$ cpalways baz bar ; echo $?
0
Stefan Lasiewski
quelle