Ocultar a saída de um comando shell somente em sucesso?

10

Escondendo a saída de um comando shell geralmente envolve o redirecionamento de stderr e stdout. Existe algum recurso interno ou comando que, por padrão, esconda a saída, mas no erro despeja toda a saída acumulada? Gostaria de executar isso como um wrapper para comandos ssh remotos. Agora eu os tenho usando redirecionamento, mas não tenho a menor idéia do que os fez falhar, e eles são muito verbosos.

EDIT: No final, criei o seguinte modelo com base na resposta de @Belmin, que ajustei um pouco para acumular todos os comandos anteriores do script, use o identificador de processo atual, automaticamente remova o log e adicione uma mensagem de erro vermelha de falha quando algo der errado. Nesse modelo, os wrappers silent iniciais serão bem-sucedidos e, em seguida, falhará no terceiro comando porque o diretório já existe:

#!/bin/sh

set -e

SILENT_LOG=/tmp/silent_log_$$.txt
trap "/bin/rm -f $SILENT_LOG" EXIT

function report_and_exit {
    cat "${SILENT_LOG}";
    echo "3[91mError running command.3[39m"
    exit 1;
}

function silent {
    $* 2>>"${SILENT_LOG}" >> "${SILENT_LOG}" || report_and_exit;
}

silent mkdir -v pepe
silent mkdir -v pepe2
silent mkdir -v pepe
silent mkdir -v pepe2
    
por Grzegorz Adam Hankiewicz 25.06.2014 / 18:18

5 respostas

3

Eu configurei uma função bash assim:

function suppress { /bin/rm --force /tmp/suppress.out 2> /dev/null; ${1+"$@"} > /tmp/suppress.out 2>&1 || cat /tmp/suppress.out; /bin/rm /tmp/suppress.out; }

Em seguida, você pode simplesmente executar o comando:

suppress foo -a bar
    
por 25.06.2014 / 19:34
6

Deve ser fácil escrever um roteiro para esse propósito.

Algo parecido com este script completamente não testado.

OUTPUT='tempfile'
program_we_want_to_capture &2>1 > $OUTPUT
[ $? -ne 0 ]; then
    cat $OUTPUT
    exit 1
fi
rm $OUTPUT

Por outro lado, para os comandos que executo como parte de um script, geralmente quero algo melhor do que simplesmente imprimir toda a saída. Costumo limitar o que vejo ao desconhecido. Aqui está um script que eu adaptei de algo que li há mais de uma década.

#!/bin/bash

the_command 2>&1 | awk '
BEGIN \
{
  # Initialize our error-detection flag.
  ErrorDetected = 0
}
# Following are regex that will simply skip all lines
# which are good and we never want to see
/ Added UserList source/ || \
/ Added User/ || \
/ init domainlist / || \
/ init iplist / || \
/ init urllist / || \
/ loading dbfile / || \
/^$/ {next} # Uninteresting message.  Skip it.

# Following are lines that we good and we always want to see
/ INFO: ready for requests / \
{
  print "  " $0 # Expected message we want to see.
  next
}

# any remaining lines are unexpected, and probably error messages.  These will be printed out and highlighted.
{
  print "->" $0 # Unexpected message.  Print it
  ErrorDetected=1
}

END \
{
  if (ErrorDetected == 1) {
    print "Unexpected messages (\"->\") detected in execution."
    exit 2
  }
}
'
exit $?
    
por 25.06.2014 / 19:11
5

Eu não acho que haja uma maneira limpa de fazer isso, a única coisa em que consigo pensar é

  • Capture a saída do comando.
  • Verifique o valor de retorno do comando e se ele falhou
    • exibe a saída capturada.

Implementar isso pode ser um projeto interessante, mas talvez além de Q & A.

    
por 25.06.2014 / 18:54
1

em breve com algo como tehcommand &>/tmp/$$ || cat /tmp/$$

depende de quanta usabilidade / digitação você quer / precisa. (por exemplo, usá-lo como um pipe ou passar o comando por argumento)

@zoredache script curto é basicamente um proto-wrapper para isso, o que daria mais robustez, lidar com concorrência, etc

    
por 25.06.2014 / 19:24
1

Tente assim:

out='command args...' || echo $out
    
por 26.06.2014 / 11:06