Acabei de encontrar uma resposta muito mais simples em esta outra questão :
output='mycommand 2>&1' || echo $output
Funciona como um encanto!
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).
Acabei de encontrar uma resposta muito mais simples em esta outra questão :
output='mycommand 2>&1' || echo $output
Funciona como um encanto!
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.
### 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>
Normalmente, em caso de erro, o comando envia mensagens para stderr
, então, para sua tarefa, você pode simplesmente suprimir stdout
mycommand > /dev/null
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
}
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
Tags error-handling scripting