将 stdout 和 stderr 存储在文件中,然后重新创建输出

将 stdout 和 stderr 存储在文件中,然后重新创建输出

我已将输出重定向到一个文件,如下所示:

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

我想精确地重现原始命令的输出./test.bash。这是我尝试过的:

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

显然,我希望输出的顺序正确。这样做的最佳方法是什么?

答案1

根据您当前的文件,可能会这样做:

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

通过对“录制脚本”进行一些更改,它可能会变得更加优雅。

答案2

如果你test.bash看起来像这样:

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

这个脚本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

应该证明输出文件经常是有序的(在我的测试中约为 37%)

问题在于扰乱并行进程、不受控制的重定向缓冲和执行速度。

使用“expect”数据包中的“unbuffer”工具解决方案(如果可以安装它)。使用:

(sleep 0.01 ; unbuffer ./test.bash)

而不是上面脚本第 4 行中的 ./test.bash 会做得很完美(0% 错误)。

答案3

如果所有输入行都以 或 开头stderr:stdout:您可以这样做:

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

或者,使用最新版本的 bash

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

相关内容