Como posso salvar stdout em um arquivo, stderr em outro arquivo, stdout + stderr em um terceiro arquivo e também obter stdout + stderr no terminal normalmente para um script de shell?
Encontrei isso em outro lugar:
exec > >(tee std_out) 2> >(tee err_out >&2)
ls # Should got to std_out
fsdfs # Command not found goes to err_out
O que é muito próximo. Se eu executar bash test.sh 2>&1 | tee output
, funcionará, mas não tenho acesso a como meu script é executado. É um sistema cicd. Preciso ser capaz de fazer a "saída combinada" de dentro do script usando exec.
Estou criando uma biblioteca de CI/CD e não consigo saber para que os clientes usariam a biblioteca, então quero levar em conta cada caso de uso.
Responder1
Simplesmente expandindo sua abordagem:
exec 2> >(tee -a stderr stdall) 1> >(tee -a stdout stdall)
O erro padrão será gravado no arquivo chamado stderr
, a saída padrão em stdout
e tanto o erro padrão quanto a saída padrão também serão gravados no console (ou o que quer que os dois descritores de arquivo estejam apontando no momento exec
da execução) e em stdall
.
tee -a
(append) é necessário para evitar stdall
que seja substituído pelo segundo tee
que começa a escrever nele.
Observe quea ordemem que os redirecionamentos são realizados é relevante: a segunda substituição do processo é afetada pelo primeiro redirecionamento, ou seja, os erros que ele emitiu seriam enviados para >(tee -a stderr stdall)
. Você pode, é claro, redirecionar o erro padrão da segunda substituição do processo para /dev/null
evitar esse efeito colateral. Redirecionar a saída padrão antes do erro padrão enviaria todos os erros para stdout
e stdall
também.
Como os comandos nas substituições de processos do Bash são executadosde forma assíncrona, não há como garantir que a saída será exibida na ordem em que foi gerada. Pior ainda, fragmentos da saída padrão e do erro padrão provavelmente acabarão aparecendo na mesma linha.
Responder2
Seu script pode ser executado sozinho $0
(definindo e verificando uma variável de ambiente para evitar recursão infinita) em vez de depender da > >(...)
construção do bash, que IMLE é caprichosa e não confiável.
if [ "$REDIRECTED" != 1 ]; then
export REDIRECTED=1
set -o pipefail
{ { "$0" | tee stdout >&3; } 2>&1 | tee stderr; } 3>&1 | tee stdboth
exit
fi
# rest of your script here
Como tee
não usa buffer de linha (nem poderia ser forçado a fazê-lo com stdbuf(1)
), a ordem dos dados gravados em stdout e stderr não será respeitada na saída final. Com um comando que usa buffer completo e grava em stdout e stderr, mesmo um buffer de linha tee
não ajudará e, pior, você pode obter linhas de saída que são metade stdout e metade stderr.
Não acho que haja alguma solução para isso usando apenas a linguagem shell e utilitários de linha de comando prontamente disponíveis.
Responder3
Estou criando uma biblioteca de CI/CD e não consigo saber para que os clientes usariam a biblioteca, então quero levar em conta cada caso de uso.
Questiono a necessidade do bash para processar as saídas, visto que este é o cenário. Idealmente, neste contexto, você desejaria registrar a data e hora da saída e fornecer a ela um ID para o tipo de saída padrão e que o aplicativo seja aquele que decide o que fazer com as mensagens.