Como redirecionar stdout e stderr para um arquivo e exibir stderr para console?

18

Eu sei como redirecionar para um arquivo e usar tee; em um nível básico. Então

$ alias outanderr='bash -c "echo stdout >&1; echo stderr >&2"'
# A fake "application" displaying both output and error messages.

$ outanderr 1>file      # redirect stdout to a file, display stderr
stderr

$ outanderr 2>file      # redirect stderr to a file, display stdout
stdout

$ outanderr 1>file 2>&1 # redirect both to a file, display nothing

$ outanderr | tee file; echo "-- file contents --" && cat file
# redirect stdout to a file, display both (note: order is messed up)
stderr
stdout
-- file contents --
stdout

$ outanderr 2>&1 | tee file; echo "-- file contents --" && cat file
# redirect both to a file, display both
stdout
stderr
-- file contents --
stdout
stderr

A pergunta é: o que escrever no lugar dos questionários para obter a saída abaixo:

$ outanderr ???; echo "-- file contents --" && cat file
# redirect both to a file, display stderr
stderr
-- file contents --
stdout
stderr

Constaints:

  • Assumindo o bash.
  • O pedido deve ser mantido no arquivo.
  • O conteúdo do stderr é exibido em tempo real linha por linha, ou seja, sem buffer.
  • Arquivos de script separados podem ser usados.
  • Magia pode ser necessária.
por TWiStErRob 19.06.2013 / 16:39

1 resposta

12
2>&1 >>outputfile | tee --append outputfile

Para um teste fácil:

echo -n >outputfile; bash -c "echo stdout >&1; echo stderr >&2" 2>&1 >>outputfile |
  tee --append outputfile; echo "outputfile:"; cat outputfile

Editar 1:

Isto funciona escrevendo stdout (somente) para o arquivo, fazendo stdout de sterr para que ele passe pelo pipe, e tendo tee escreva sua saída para o mesmo arquivo.

As duas gravações devem ser feitas no modo de acréscimo ( >> em vez de > ), caso contrário, ambas sobrescreveriam as outras saídas.

Como o pipe é um buffer, não há garantia de que a saída apareça no arquivo na ordem correta. Isso nem sequer mudaria se um aplicativo estivesse conectado a ambos os descritores de arquivo (dois canais). Para a ordem garantida, ambas as saídas teriam que passar pelo mesmo canal e ser marcadas respectivamente. Ou você precisaria de algumas coisas realmente extravagantes:

  1. Se stdout e stderr fossem redirecionados para um arquivo (não para o mesmo arquivo!) e os dois arquivos estivessem em um volume FUSE, o módulo FUSE poderia marcar cada gravação com um timestamp para que um segundo aplicativo pudesse classificar os dados corretamente e combiná-lo para o arquivo de saída real. Ou você não marca os dados, mas faz com que o módulo crie o arquivo de saída combinado. Muito provavelmente ainda não há nenhum módulo FUSE que faça isso ...
  2. A stdout e stderr podem ser direcionadas para /dev/null . As saídas do aplicativo seriam separadas, executando-o em strace -f -s 32000 -e trace=write . Você teria que inverter o escape nesse caso. Escusado será dizer que a aplicação não corre mais depressa ao ser rastreada.
  3. Talvez o mesmo possa ser alcançado usando um módulo FUSE existente e simples e rastreando o módulo em vez do aplicativo. Isso pode ser mais rápido do que rastrear o aplicativo porque (ou melhor: se) o módulo provavelmente tem muito menos syscalls que o aplicativo.
  4. Se o aplicativo em si pode ser modificado: O aplicativo pode ser interrompido após cada saída (mas acho que isso é possível somente a partir do interior) e continuar somente depois de receber o sinal s (SIGUSR1 ou SIGCONT). A leitura do aplicativo do pipe teria que verificar o pipe e o arquivo quanto a novos dados e enviar o sinal após cada novo dado. Dependendo do tipo de aplicação, isso pode ser mais rápido ou mais lento que o método strace. FUSE seria a solução de velocidade máxima.
por 19.06.2013 / 17:16