Como posso suprimir a saída somente se o comando for bem-sucedido?

20

Eu gostaria de simplificar a saída de um script suprimindo a saída de comandos secundários que geralmente são bem-sucedidos.

No entanto, usar -q neles oculta a saída quando eles ocasionalmente falham, então não tenho como entender o erro. Além disso, esses comandos registram sua saída em stderr .

Existe uma maneira de suprimir a saída de um comando somente se for bem-sucedida ?

Por exemplo (mas não limitado a) algo como isto:

mycommand | fingerscrossed

Se tudo correr bem, fingerscrossed detecta a saída e a descarta. Senão ecoa na saída padrão ou de erro (o que for).

    
por Matthieu Napoli 18.01.2016 / 18:04

6 respostas

3

Acabei de encontrar uma resposta muito mais simples em esta outra questão :

output='mycommand 2>&1' || echo $output

Funciona como um encanto!

    
por 20.01.2016 / 10:28
33

moreutils O comando ' chronic faz exatamente isso:

chronic mycommand

irá engolir a saída de mycommand , a menos que falhe, caso em que a saída é exibida.

    
por 18.01.2016 / 18:07
11
### do this bit once at the top of your script
divert=
exec 3<>"${divert:=$(mktmp)}" 4<>/dev/null
rm -- "$divert"; unset divert
### then do this bit as often as needed
command >&3 2>&3
cat <&3 >&"$(((RTN=$?)?2:4))"

Isso provavelmente deve fazer o truque. Ele armazenará em buffer a saída de cada command em um arquivo temporário excluído, e depois extrairá sua saída em /dev/null ou stderr, dependendo de seu status de retorno não ser zero ou não. Como o arquivo temporário é excluído antecipadamente, ele não pode ser lido por nenhum processo, mas o shell atual e seus filhos em seu descritor de arquivo (e não sneaky /proc/$pid/fd snoops com as permissões apropriadas) , e não exigem limpeza quando você passa.

Talvez uma solução mais conveniente em sistemas Linux:

divert(){
    "$@" >&3 2>&3 ||
    eval "cat <&3
          return $?"
}   3<<"" 3<>/dev/fd/3

... que, na maioria dos shells, funciona como o outro, exceto que você pode chamá-lo como: divert some simple-command with args . Cuidado com os comandos de alta saída em "$@" , embora para dash , yash , ou algumas outras shells que fazem aqui-documents com pipes - eu acho que pode ser possível nessas shells preencher o buffer de tubos ( em um padrão de cerca de 128kb em linuxes) e assim deadlock. Isso não deve ser uma preocupação para ksh , mksh , bash , zsh ou o shell Bourne, embora todos esses façam basicamente a mesma coisa que explicitamente acima com exec . / p>     

por 18.01.2016 / 19:55
9

Normalmente, em caso de erro, o comando envia mensagens para stderr , então, para sua tarefa, você pode simplesmente suprimir stdout

mycommand > /dev/null
    
por 18.01.2016 / 19:25
4

Para fazer sua própria crônica

my_chronic() {
  tmp=$(mktemp) || return # this will be the temp file w/ the output
  "$@"  > "$tmp" 2>&1 # this should run the command, respecting all arguments
  ret=$?
  [ "$ret" -eq 0 ] || cat "$tmp"  # if $? (the return of the last run command) is not zero, cat the temp file
  rm -f "$tmp"
  return "$ret" # return the exit status of the command
}
    
por 19.01.2016 / 01:57
3

Eu faço algo assim em meus makefiles:

if (mycommand) &> mycommand.log; then 
  echo success 
else 
  c=$?; 
  echo;echo -e "Bad result from previous command, see mycommand.log for more details";echo;
  command_to_run_on_fail
  (exit $c)
fi

Adaptando isso à sua situação, você poderia fazer algo assim:

if ! (mycommand) &> mycommand.log; then 
  c=$?; 
  cat mycommand.log
  rm mycommand.log
  (exit $c)
fi

Portanto, "if" executa o comando e canaliza a saída para mycommand.log. Se você precisa pegar stdout vs stdout vs qualquer coisa, talvez seja necessário alterar o comando de canal '& >' para '>'. Se o comando falhar, capture o código de erro, imprima o conteúdo de mycommand.log, remova mycommand.log e, finalmente, retorne com o código de erro original.

Sem o (exit $ c) você retornaria com o código de saída que corresponde ao que o comando 'rm' retornou.

Finalmente, se você quiser um forro, algo assim funcionaria.

mycommand &> mycommand.log || cat mycommand.log; rm mycommand.log
    
por 18.01.2016 / 20:38