Como deixar o comando 'cp' não acionar um erro quando o arquivo de origem não existe?

59

Estou usando o Mac OS X. Estou tentando copiar alguns arquivos com o comando cp para um script de construção como este.

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

Mas este comando dispara um erro se não houver arquivo .h no diretório ./src. Como fazer o comando não disparar o erro? (falha silenciosa) O erro faz com que o resultado da compilação falhe, mas eu só quero copiar quando houver apenas algum arquivo de cabeçalho.

Eonil
fonte

Respostas:

69

Se você está falando sobre a mensagem de erro, pode suprimi-la enviando-a para o bloco de bits:

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

Se você deseja suprimir o código de saída e a mensagem de erro:

cp ./src/*/*.h ./aaa 2>/dev/null || :
Dennis Williamson
fonte
8
Seria bom explicar o que :significa neste contexto.
Piotr Dobrogost
23
@PiotrDobrogost: No Bash e em algumas outras conchas, o cólon é um utilitário nulo (no-op). É especificado pelo POSIX . Como sempre retorna true, é usado aqui para suprimir o código de saída de uma falha cp(caso isso seja desejado). O shell embutido truepoderia ser usado e seria mais legível.
Dennis Williamson
11
Isso também ignorará outros erros (o diretório de origem / destino não existe, o arquivo de origem existe, mas não é legível, disco cheio, sistema de arquivos somente leitura, erro de IO, cpnão está de PATHalguma forma ...)
Vladimir Panteleev
erro de sintaxe próximo ao token inesperado `|| '
thang
13

Você está procurando algo ao longo das linhas de

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

(Infelizmente, a -fopção não é o droid que você está procurando.)

Se você quiser combinar com uma glob, isso não funcionará; use em findvez disso, por exemplo:

find ./src -name \*.h -exec cp {} ./destination \;
Brad Ackerman
fonte
Observe que existe um possível problema do TOCTOU com essa abordagem (por exemplo, se você usar set -ee o arquivo desaparecer entre [as cpchamadas e o invocador, seu script falhará).
Vladimir Panteleev
9

Pergunta antiga, mas ainda pode ser relevante para os outros.
Se você não precisar usar o cp, tente com o rsync.
Para copiar todos os arquivos de uma origem para um diretório de destino, execute:

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

O Rsync vem com a maioria dos sistemas Unix, como Linux, Mac OS X ou FreeBSD.

senhor
fonte
4
Você pode usar o rsync em vez do cp, adicionando o parâmetro --ignore-missing-args: rsync -av --ignore-missing-args ./src/*/*.h ./aaaIsso tem a vantagem de --ignore-errorsque os únicos erros ignorados são aqueles relacionados a arquivos de origem que não existem. A --ignore-errorscada erro é ignorado, o que pode ser perigoso. Além disso, leve em consideração que esse parâmetro é relativamente recente, portanto, pode não estar presente nas versões antigas do rsync.
jesjimher
6

Canalizar o resultado como true garante que o comando sempre seja bem-sucedido. Eu tentei isso no Linux, mas não em nenhum Mac OS:

cp ./src/*/*.h ./aaa | true
Vivek
fonte
5
O tubo simples |é sempre executado enquanto ||é feito apenas em caso de erro. E truegeralmente é um binário, enquanto o cólon :está embutido e não consome um PID.
6--15
Um script bash no MacOS - Yosemite contendo o comando "cp ./src/*/*.h ./aaa" não gera erros se os arquivos .h não existirem.
Vivek
2

Você pode forçar o status de erro correto. Com uma função:

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

Dado o seguinte:

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

A cópia regular retornará um erro. Ele retornará um status de saída 1.

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

Se usarmos a função cpalways () acima, quaisquer erros serão ocultados:

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