Armazene stdout e stderr no arquivo e, em seguida, recrie a saída posteriormente

1

Eu redirecionei a saída para um arquivo assim:

$ ./test.bash 2> >(sed 's/^/stderr: /' >> output) > >(sed 's/^/stdout: /' >> output)
$ cat output
  stdout: Hello World!
  stderr: error

Eu gostaria de reproduzir precisamente a saída do comando original ./test.bash . Isso é o que eu tentei:

$ cat output | tee >(grep '^stdout: '|sed 's/^stdout: //') >(grep '^stderr: '|sed 's/^stderr: //' 1>&2) >/dev/null 2>&1 | cat
  error
  Hello World!

Obviamente, gostaria que a saída estivesse na ordem correta. Qual é a melhor maneira de fazer isso?

    
por Jack 25.03.2015 / 18:28

3 respostas

4

Dependendo do seu arquivo atual, isso provavelmente aconteceria:

awk '
    /^stdout:/ { print substr($0, 9) } 
    /^stderr:/ { print substr($0, 9) > "/dev/stderr" }
    ' output

Pode ficar um pouco mais elegante com algumas alterações no seu "script de gravação".

    
por 25.03.2015 / 18:47
2

se o seu test.bash for assim:

echo "Hello World!"; echo error >&2

este script loop.sh :

./test.bash &> original ; echo original: ; cat original;     ok=0 ; er=0
for i in {1..100}; do
   rm output ; printf "(ok%d:er%d) running again: " $ok $er
   ./test.bash 2> >(cat >>output) > >(cat >>output)  #<-EXAMINED COMMAND
   if diff output original >/dev/null;
      then printf "result equal...."; ((ok++))
      else printf "result DIFFERENT"; ((er++)); fi
done

deve provar que o arquivo de saída é frequentemente ordenado erroneamente (~ 37% no meu teste)

O problema é mexer com processos paralelos, buffering de redirecionamento descontrolado e velocidades de execução.

Solução com a ferramenta "unbuffer" do pacote "expect" (se você puder instalá-lo). Usando:

(sleep 0.01 ; unbuffer ./test.bash)

em vez de apenas ./test.bash na 4ª linha do script acima, será perfeito (erros de 0%).

    
por 25.03.2015 / 19:56
0

Se todas as suas linhas de entrada começarem com stderr: ou stdout: , você poderia fazer:

perl -ne 's/^std(...):\s*//; $1 eq "err" ? print STDERR : print' output

Ou com versões recentes do bash

while read -r out line; do
    [[ $out =~ ^stderr ]] && echo "$line" >&2 || echo "$line"
done < output 
    
por 25.03.2015 / 19:16