Um comando como mv foo* ~/bar/
produz essa mensagem no stderr se não houver arquivos correspondentes foo*
.
mv: cannot stat `foo*': No such file or directory
No entanto, no script em que estou trabalhando nesse caso, ficaria bem e gostaria de omitir essa mensagem de nossos logs.
Existe alguma maneira agradável de dizer mv
para ficar quieto, mesmo que nada tenha sido movido?
mv foo* ~/bar/ 2> /dev/null
?mv
. :) Mas isso serve, é claro.mv
implementações suportarem uma-q
opção para silenciá-las, mas isso não faz parte da especificação POSIXmv
. Omv
coreutils no GNU, por exemplo, não possui essa opção.Respostas:
Você está procurando por isso?
fonte
set -e
(que deve ser usado em todos os scripts de shell) falhará. você pode adicionar a|| true
para desativar a verificação de um único comando.set -e
não deve ser usado em todos os scripts de shell, em muitos casos, torna o gerenciamento de erros ainda mais complexo do que é sem.Na verdade, não acho que o silêncio
mv
é uma boa abordagem (lembre-se de que você também pode denunciar outras coisas que podem ser interessantes ... por exemplo, em falta~/bar
). Você deseja silenciá-lo apenas no caso de sua expressão glob não retornar resultados. De fato, prefiro não executá-lo.Não parece muito atraente e funciona apenas em
bash
.OU
somente exceto se você estiver
bash
com onullglob
conjunto. Você paga um preço de 3x a repetição do padrão glob.fonte
foo*
quando é o único no diretório atual que corresponde ao globfoo*
. Isso pode ser contornado com uma expressão glob que não combina literalmente, é difícil. Por exemplo[ 'fo[o]*' = "$(echo fo[o]*)" ] || mv fo[o]* ~/bar/
.find . -maxdepth 1 -name 'foo*' -type f -print0 | xargs -0r mv -t ~/bar/
- O GNU
mv
possui uma boa opção "destination first" (-t
) exargs
pode pular a execução de seu comando se não houver entrada (-r
). Usar-print0
e-0
correspondentemente garante que não haja confusão quando os nomes de arquivos contiverem espaços e outras coisas "engraçadas".fonte
-maxdepth
,-print0
,-0
e-r
também são extensões GNU (embora alguns deles são encontrados em outras implementações de hoje em dia).mv
.É importante perceber que, na verdade, é o shell que o expande
foo*
para a lista de nomes de arquivos correspondentes, para que haja pouco omv
que fazer.O problema aqui é que, quando um glob não corresponde, algumas conchas como
bash
(e a maioria das conchas semelhantes a Bourne, esse comportamento de buggy foi realmente introduzido pelo shell Bourne no final dos anos 70) passam o padrão literalmente para o comando.Portanto, aqui, quando
foo*
não corresponde a nenhum arquivo, em vez de interromper o comando (como os shells pré-Bourne e vários shells modernos), o shell passa umfoo*
arquivo literal paramv
, basicamente pedindomv
para mover o arquivo chamadofoo*
.Esse arquivo não existe. Se isso acontecesse, ele realmente corresponderia ao padrão, então
mv
relata um erro. Se o padrão tivesse sidofoo[xy]
substituído,mv
poderia mover acidentalmente um arquivo chamado emfoo[xy]
vez dos arquivosfoox
efooy
.Agora, mesmo nos shells que não têm esse problema (pré-Bourne, csh, tcsh, fish, zsh, bash -O failglob), você ainda receberia um erro
mv foo* ~/bar
, mas desta vez pelo shell.Se você quiser considerar que não é um erro, se não houver nenhum arquivo correspondente
foo*
e, nesse caso, não mover nada, você deve criar a lista de arquivos primeiro (de uma maneira que não cause erro, usando anullglob
opção de algumas conchas) e, em seguida, apenas chamarmv
é a lista não está vazia.Isso seria melhor do que ocultar todos os erros
mv
(como adicionar2> /dev/null
) como semv
falhasse por qualquer outro motivo, você provavelmente ainda desejaria saber o motivo.em zsh
Ou use uma função anônima para evitar o uso de uma variável temporária:
zsh
é um daqueles shells que não possuem o bug Bourne e relatam um erro sem executar o comando quando um glob não corresponde (e anullglob
opção não foi ativada), então aqui, você pode ocultarzsh
o erro e restaurar stderr paramv
que você ainda veja osmv
erros, se houver, mas não o erro sobre os globs não correspondentes:Ou você pode usar o
zargs
que também evitaria problemas se afoo*
glob se expandisse para arquivos demais.No ksh93:
Na festança:
bash
não possui sintaxe para ativarnullglob
apenas um glob, e afailglob
opção é canceladanullglob
, sendo necessário itens como:ou defina as opções em um subshell para salvar, salve-as antes e restaure-as depois.
No
yash
No
fish
No shell do peixe, o comportamento nullglob é o padrão para o
set
comando, portanto, é apenas:POSIXly
Não há
nullglob
opção no POSIXsh
e nenhuma matriz além dos parâmetros posicionais. Existe um truque que você pode usar para detectar se um glob corresponde ou não:Usando a
foo[*]
efoo*
glob, podemos diferenciar entre o caso em que não há arquivo correspondente e aquele em que há um arquivo que é chamadofoo*
(o queset -- foo*
não poderia ser feito).Mais leitura:
fonte
Provavelmente não é o melhor, mas você pode usar o
find
comando para verificar se a pasta está vazia ou não:fonte
foo*
caminho de pesquisa literal parafind
.Estou assumindo que você está usando o bash, porque esse erro depende do comportamento do bash para expandir globs incomparáveis para si mesmos. (Em comparação, o zsh gera um erro ao tentar expandir um globo incomparável.)
Então, e a seguinte solução alternativa?
Isso ignorará silenciosamente o
mv
ifls -d foo*
falhar, enquanto ainda registrará erros sels foo*
for bem-sucedido, masmv
falhar. (Cuidado,ls foo*
pode falhar por outros motivos quefoo*
não existem, por exemplo, direitos insuficientes, problemas com o FS, etc., para que essas condições sejam silenciosamente ignoradas por esta solução.)fonte
bash
). +1 por considerar o fato de quemv
pode falhar por outros motivos quefoo*
não existem.ls
comando não seria muito claro para futuros leitores, pelo menos sem um comentário.)ls -d foo*
também pode retornar com um status de saída diferente de zero por outros motivos, como após umln -s /nowhere foobar
(pelo menos com algumasls
implementações).Você pode fazer por exemplo
mv 1>/dev/null 2>&1 foo* ~/bar/
oumv foo* ~/bar/ 1&>2
Para mais detalhes, consulte: http://mywiki.wooledge.org/BashFAQ/055
fonte
mv foo* ~/bar/ 1&>2
não silenciar o comando, ele envia o que estaria no stdout para também estar no stderr./dev/null
comNUL
1
e2
significa?Você pode trapacear (portably) com
perl
:fonte
Se você vai usar o Perl, é melhor ir até o fim:
ou como uma linha:
(Para detalhes do
move
comando, consulte a documentação para File :: Copy .)fonte
Em vez de
você pode fazer
Simples, legível :)
fonte
cp
nemrm
estão em silêncio, sefoo*
não existe.Se o comando Above é bem-sucedido ou não, podemos encontrar pelo status de saída do comando anterior
se a saída de eco $? é diferente de 0 significa comando sem êxito se a saída for 0 significa comando com êxito
fonte