Comment laisser la commande 'cp' ne déclencher une erreur lorsque le fichier source n'existe pas?

59

J'utilise Mac OS X. J'essaie de copier certains fichiers avec la commande cp pour un script de construction comme celui-ci.

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

Mais cette commande déclenche une erreur s'il n'y a pas de fichier .h dans le répertoire ./src. Comment faire pour que la commande ne déclenche pas l'erreur? (échec silencieux) L'erreur fait échouer le résultat de la construction, mais je veux simplement copier quand il y a seulement un fichier d'en-tête.

Eonil
la source

Réponses:

69

Si vous parlez du message d'erreur, vous pouvez le supprimer en l'envoyant au compartiment des bits:

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

Si vous souhaitez supprimer le code de sortie et le message d'erreur:

cp ./src/*/*.h ./aaa 2>/dev/null || :
Dennis Williamson
la source
8
Il serait bon d’expliquer ce que :signifie dans ce contexte.
Piotr Dobrogost
23
@PiotrDobrogost: Dans Bash et quelques autres shells, le colon est un utilitaire nul (no-op). C'est spécifié par POSIX . Puisqu'il renvoie toujours true, il est utilisé ici pour supprimer le code de sortie d'un échoué cp(si cela est souhaité). Le shell intégré truepourrait être utilisé à la place et serait plus lisible.
Dennis Williamson
1
Cela ignorera également les autres erreurs (le répertoire source / destination n'existe pas, le fichier source existe mais n'est pas lisible, disque plein, système de fichiers en lecture seule, erreur d'entrée-sortie, cpne pas être en PATHquelque sorte ...)
Vladimir Panteleev
erreur de syntaxe près du jeton inattendu `|| '
thang
13

Vous cherchez quelque chose le long des lignes de

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

(Malheureusement, l' -foption n'est pas le droïde que vous recherchez.)

Si vous voulez faire correspondre un glob, cela ne fonctionnera pas; utilisez à la findplace, par exemple:

find ./src -name \*.h -exec cp {} ./destination \;
Brad Ackerman
la source
Notez qu’une telle approche peut poser problème avec TOCTOU (par exemple, si vous utilisez set -eet que le fichier disparaît entre le [et les cpinvocations, votre script se bloque).
Vladimir Panteleev
9

Ancienne question, mais pourrait toujours être pertinente pour les autres.
Si vous n'avez pas besoin d'utiliser cp, vous pouvez essayer avec rsync.
Pour copier tous les fichiers d'une source vers un répertoire de destination, exécutez:

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

Rsync est fourni avec la plupart des systèmes de type Unix tels que Linux, Mac OS X ou FreeBSD.

mre
la source
4
Vous pouvez utiliser rsync au lieu de cp, en ajoutant le paramètre suivant --ignore-missing-args: rsync -av --ignore-missing-args ./src/*/*.h ./aaaceci présente l’avantage sur le fait --ignore-errorsque les seules erreurs ignorées sont celles liées aux fichiers source non existants. Avec --ignore-errorschaque erreur est ignorée, ce qui peut être dangereux. De plus, tenez compte du fait que ce paramètre est assez récent, il pourrait donc ne pas être présent dans les anciennes versions de rsync.
jesjimher
6

Piping le résultat sur true garantit que la commande réussira toujours. J'ai essayé cela sous Linux mais pas sous Mac OS:

cp ./src/*/*.h ./aaa | true
Vivek
la source
5
Le tuyau simple |est toujours exécuté alors que ce ||n'est fait qu'en cas d'erreur. Et trueest généralement un binaire alors que le côlon :est intégré et ne consomme pas de PID.
ott--
Un script bash sur MacOS - Yosemite contenant la commande "cp ./src/*/*.h ./aaa" n'erreur pas si les fichiers .h n'existent pas.
Vivek
2

Vous pouvez forcer le statut d'erreur correct. Avec une fonction:

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

Compte tenu de ce qui suit:

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

Une copie normale renverra une erreur. Il retournera un statut de sortie de 1.

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

Si nous utilisons la fonction cpalways () ci-dessus, toutes les erreurs seront masquées:

$ cpalways baz bar ; echo $?
0
$ cpalways foo bar ; echo $?
0
$ cpalways baz bar ; echo $?
0
Stefan Lasiewski
la source