¿Cómo dejar que el comando 'cp' no active un error cuando el archivo fuente no existe?

59

Estoy usando Mac OS X. Estoy tratando de copiar algunos archivos con el comando cp para un script de compilación como este.

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

Pero este comando genera un error si no hay un archivo .h en el directorio ./src. ¿Cómo hacer que el comando no active el error? (falla silenciosa) El error hace que falle el resultado de la compilación, pero solo quiero copiar cuando solo hay algún archivo de encabezado.

Eonil
fuente

Respuestas:

69

Si habla del mensaje de error, puede suprimirlo enviándolo al depósito de bits:

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

Si desea suprimir el código de salida y el mensaje de error:

cp ./src/*/*.h ./aaa 2>/dev/null || :
Dennis Williamson
fuente
8
Sería bueno explicar qué :significa en este contexto.
Piotr Dobrogost
23
@PiotrDobrogost: en Bash y algunas otras conchas, el colon es una utilidad nula (no-op). Está especificado por POSIX . Como siempre devuelve verdadero, se usa aquí para suprimir el código de salida de un error cp(si se desea). El shell incorporado truepodría utilizarse en su lugar y sería más legible.
Dennis Williamson
1
Esto también ignorará otros errores (el directorio fuente / destino no existe, el archivo fuente existe pero no es legible, el disco está lleno, el sistema de archivos de solo lectura, el error IO, cpno está de PATHalguna manera ...)
Vladimir Panteleev
error de sintaxis cerca del token inesperado `|| '
thang
13

Estás buscando algo en la línea de

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

(Desafortunadamente, la -fopción no es el droide que estás buscando).

Si quieres igualar un globo, eso no funcionará; utilizar finden su lugar, por ejemplo:

find ./src -name \*.h -exec cp {} ./destination \;
Brad Ackerman
fuente
Tenga en cuenta que existe un posible problema de TOCTOU con este enfoque (por ejemplo, si lo usa set -ey el archivo desaparece entre [las cpinvocaciones y, el script se bloqueará).
Vladimir Panteleev
9

Antigua pregunta, pero aún podría ser relevante para otros.
Si no necesita usar cp, puede intentarlo con rsync.
Para copiar todos los archivos de un origen a un directorio de destino, ejecute:

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

Rsync viene con la mayoría de los sistemas tipo Unix, como Linux, Mac OS X o FreeBSD.

mre
fuente
44
Puede usar rsync en lugar de cp, agregando el parámetro --ignore-missing-args: rsync -av --ignore-missing-args ./src/*/*.h ./aaaEsto tiene la ventaja sobre --ignore-errorsque los únicos errores ignorados son aquellos relacionados con los archivos fuente que no existen. Con --ignore-errorscada error se ignora, lo que puede ser peligroso. Además, tenga en cuenta que este parámetro es bastante reciente, por lo que podría no estar presente en las versiones anteriores de rsync.
jesjimher
6

Canalizar el resultado a verdadero asegura que el comando siempre tendrá éxito. He intentado esto en Linux pero no en ningún Mac OS:

cp ./src/*/*.h ./aaa | true
Vivek
fuente
55
La tubería simple |siempre se ejecuta mientras ||solo se realiza en caso de error. Y truegeneralmente es un sistema binario, mientras que el colon :está integrado y no consume un PID.
ott--
Un script bash en MacOS - Yosemite que contiene el comando "cp ./src/*/*.h ./aaa" no genera errores si los archivos .h no existen.
Vivek
2

Podría forzar el estado de error correcto. Con una función:

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

Dado lo siguiente:

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

La copia regular devolverá un error. Devolverá un estado de salida de 1.

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

Si usamos la función cpalways () anterior, se ocultarán los errores:

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