Como posso usar a magia BASH para conseguir isso?
Quero ver apenas a saída stderr na tela,
mas quero que stdout e stderr sejam gravados em um arquivo.
Esclarecimento: Eu quero que stdout e stderr terminem no mesmo arquivo. Na ordem em que eles acontecem.
Infelizmente, nenhuma das respostas abaixo faz isso.
bash
shell
io-redirection
Andreas
fonte
fonte
Respostas:
Mesmo sem nenhum redirecionamento, ou apenas com nada
>logfile 2>&1
, você não tem garantia de ver a saída em ordem de geração.Para iniciantes, o stdout do aplicativo será buffer de linha (para tty) ou buffer (para um pipeline), mas o stderr não é armazenado em buffer, portanto, os relacionamentos entre a ordem de saída são interrompidos no que diz respeito ao leitor. Os estágios subseqüentes em qualquer pipeline que você possa inventar não terão acesso determinista aos dois fluxos (eles são conceitualmente coisas acontecendo paralelamente e você estará sempre sujeito ao agendador - se no momento em que o leitor tiver uma fatia, o escritor já terá gravado nos dois pipes, você não pode dizer qual veio primeiro).
"[A ordem que eles acontecem" só é realmente conhecida pelo aplicativo. A ordenação da saída no stdout / stderr é um problema bem conhecido - clássico, talvez -.
fonte
Quando você usa a construção:
1>stdout.log 2>&1
tanto stderr e stdout redirecionado para o arquivo porque o stdout redirecionamento é configurado antes da stderr redirecionamento.Se você inverter a ordem, poderá redirecionar o stdout para um arquivo e, em seguida, copiar o stderr para o stdout, para que você possa canalizá-lo
tee
.fonte
tee -a
o mesmo arquivo usado1>
para somar as duas saídas no mesmo arquivo. Algo como:./test 2>&1 1>out+err.log | tee -a out+err.log
wget -O - www.google.de
comigo. (comparar com a solução a seguir)tee -a
não funcionará de maneira confiável para ter a mesma saída que estaria no console se nada fosse redirecionado. A saída que passatee
pode ser um pouco atrasada em comparação com a saída que vem diretamente do comando e, portanto, pode aparecer mais tarde no log.Consegui fazer isso colocando a seguinte linha no topo de um script bash:
Isso irá redirecionar o stdout para o arquivo
log
(1>>log
), depois tee stderr para o arquivolog
(2> >(tee -a log
) e direcioná-lo de volta para o stderr (>&2)
. Dessa forma, recebo um único arquivolog
, que mostra stdout e stderr em ordem, e o stderr também é exibido na tela como de costume.O problema é que ele só parece funcionar quando anexo ao arquivo. Se eu não anexar, parece que os dois redirecionamentos se atrapalham, e eu só recebo o que sair por último.
fonte
Você deseja duplicar o fluxo de erros para que apareça no console e no arquivo de log. A ferramenta para isso é
tee
, e tudo que você precisa fazer é aplicá-la ao fluxo de erros. Infelizmente, não há nenhuma construção de shell padrão para canalizar o fluxo de erro de um comando para outro comando; portanto, é necessário um pequeno rearranjo do descritor de arquivo.fonte
tee
introduz um atraso aqui também. Eu não acho que exista uma solução pura de casca. Na verdade, eu me pergunto se existe uma solução sem modificar o aplicativo de alguma forma.Para escrever stderr na tela e escrever AMBOS stderr e stdout em um arquivo - E fazer com que as linhas para stderr e stdout saiam na mesma sequência que seriam se ambas fossem gravadas na tela:
Acabou sendo um problema difícil, especialmente a parte de ter a "mesma sequência" que você esperaria se simplesmente as escrevesse na tela. Em termos simples: escreva cada um em seu próprio arquivo, faça alguma mágica do processo em segundo plano para marcar cada linha (em cada arquivo) com a hora exata em que a linha foi produzida e depois: "tail --follow" o arquivo stderr na tela , mas para ver AMBOS "stderr" e "stdout" juntos - em sequência - classifique os dois arquivos (com marcações de tempo exato em cada linha) juntos.
Código:
Sim, isso parece elaborado e resulta em 4 arquivos de saída (2 dos quais você pode excluir). Parece que este é um problema difícil de resolver, por isso foram necessários vários mecanismos.
No final, para ver os resultados de ambos stdout e stderr na sequência que você esperaria, execute o seguinte:
A única razão pela qual a sequência está pelo menos muito próxima do que seria se stdout e stderr simplesmente tivessem ido para a tela é: Cada linha é marcada com um carimbo de data / hora até o milissegundo.
Para ver o stderr na tela à medida que o processo avança, use o seguinte:
Espero que ajude alguém que chegou aqui muito tempo depois que a pergunta original foi feita.
fonte
Seja
f
o comando que você deseja que seja executado, então estedeve dar o que você deseja. Por exemplo,
wget -O - www.google.de
ficaria assim:fonte
Dado o que eu li aqui, a única solução que eu posso ver seria preceder cada linha se STOUT ou STERR com um horário / timestamp. date +% s chegaria a segundos, mas é mais lento para manter a ordem. Além disso, o log precisaria, de alguma forma, ser classificado. Mais trabalho do que sou capaz.
fonte
Eu lutei com esse requisito exato e, no final, não consegui encontrar uma solução simples. O que acabei fazendo foi o seguinte:
Ele anexa stdout e stderr, na ordem intercalada apropriada, ao arquivo de log. E se ocorrer algum erro (conforme determinado pelo status de saída do comando), ele envia a saída inteira (stdout e stderr) para stdout, novamente na ordem intercalada adequada. Achei que esse era um compromisso razoável para minhas necessidades. Se você deseja um arquivo de log de execução única em vez de um arquivo de várias execuções crescente, é ainda mais simples:
fonte
stderr para substituído por comando
tee -a
e stdout anexando ao mesmo arquivo:e note: para garantir também a ordem correta (mas sem o stderr-show), existe o comando 'unbuffer' das ferramentas 'expect', que simula o tty e mantém o stdout / err em ordem, como seria mostrado no terminal:
fonte