Duplicando a saída do stderr e mesclando com o stderr no bash sem alterar a ordem

2

Eu quero escrever stderr e stdout em um arquivo de log e imprimir stderr no terminal (ou dispositivo de saída padrão).

Motivação: Eu tenho um comando no meu crontab e quero registrar todos os seus resultados em um arquivo, e quero que o cron me mande um e-mail se houver algo escrito no erro saída.

Eu tive algum sucesso com isso:

(echo out1; echo err1 1>&2; echo out2; echo err2 1>&2) \
    2> >(tee -a log) \
    1>>log

Ou:

(echo err1 1>&2; echo out2; echo err2 1>&2) \
    3>&1 \
    1> >(tee -a log 1>/dev/null) \
    2> >(tee -a log 1>&3)

Ou com exec:

exec 3>&1
exec 1> >(tee -a log2 1>/dev/null)
exec 2> >(tee -a log2 1>&3)
echo out1; echo err1 1>&2; echo out2; echo err2 1>&2

(A terceira solução também registra o prompt, por isso não funciona em um shell interativo.)

O problema com as três soluções é que o arquivo de log contém as linhas em uma ordem diferente:

out1
out2
err1
err2

Em vez disso:

out1
err1
out2
err2

Existe uma maneira de evitar isso? Algo como 2>&1 , que duplica a saída em si, e não o descritor.

Existe um muito semelhante pergunta para Windows

    
por TPE 16.06.2018 / 16:30

1 resposta

0

Eu acho que você quer simplificar e otimizar isso o máximo possível. Agora não consigo pensar em nenhuma solução melhor do que ir passo a passo. Ou seja,

$ echo out1 >> log
$ echo err1 | tee -a log >&2
err1
$ echo out2 >> log
$ echo err2 | tee -a log >&2
err2
$ cat log
out1
err1
out2
err2

Bem, você pode usar um coprocess, para que você não precise chamar tee muitas vezes, se isso for importante para você.

$ coproc tee -a log
[1] 26417
$ echo out1 >> log
$ echo err1 >&"${COPROC[1]}"
$ echo out2 >> log
$ echo err2 >&"${COPROC[1]}"
$ cat log
out1
err1
out2
err2

Agora, sejam quais forem os erros, eles estão esperando no canal de saída do coprocess. Se você só precisa verificar se há alguma coisa lá, isso vai fazer:

$ timeout 1 head -n1 <&"${COPROC[0]}" >/dev/null && echo yes # or something else
yes

Se você quiser reutilizar os erros, convém modificar o coprocessamento para se adequar ao seu objetivo.

Você também pode definir o redirecionamento para scripts e binários. Contanto que eles não tenham redirecionamentos conectados, é claro. Assim você pode fazer isso,

$ some_executable 2>&"${COPROC[1]}" >>log

E a lógica permanece a mesma.

    
por 16.06.2018 / 17:01