首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >同步保存stdout、stderr和stdout+stderr

同步保存stdout、stderr和stdout+stderr
EN

Stack Overflow用户
提问于 2010-12-21 09:29:46
回答 3查看 5.5K关注 0票数 10

为了测试目的,我想分别保存stdout和stderr,以供后续代码检查。例如,带有错误输入的测试运行应该导致输出到stderr,但是stdout上没有任何结果,而具有正确输入的测试运行应该导致输出到stdout,但是没有输出到stderr。保存必须是同步的,以避免使用测试的竞争条件(因此我不能使用过程替代)。

为了能够在事后调试测试,我还需要在输出的序列中看到stdout和stderr。因此,我要么将它们保存到相同的文件/变量/任何东西中,要么将它们分别保存到终端。

为了测试发生了哪些错误,我还需要命令的退出代码。

由于效率和准确性的原因,我当然不能每次测试两次。

例如,是否可以在同一个命令中将stdout重定向到stdout.log,stderr重定向到stderr.log,并将两者重定向到output.log?还是对stdout和stderr分别使用同步 tee命令?还是保存stdout和stderr的副本以分离变量?

Update:看起来tim的解决方案几乎可以工作(修改为在终端上输出,而不是登录到all.log):

代码语言:javascript
复制
$ set -o pipefail
$ {
    {
        echo foo | tee stdout.log 2>&3 3>&-
    } 2>&1 >&4 4>&- | tee stderr.log 2>&3 3>&-
} 3>&2 4>&1
foo
$ cat stdout.log
foo
$ cat stderr.log
$ {
    {
        echo foo >&2 | tee stdout.log 2>&3 3>&-
    } 2>&1 >&4 4>&- | tee stderr.log 2>&3 3>&-
} 3>&2 4>&1
foo
$ cat stdout.log
$ cat stderr.log
foo
$ bar=$({
    {
        echo foo | tee stdout.log 2>&3 3>&-
    } 2>&1 >&4 4>&- | tee stderr.log 2>&3 3>&-
} 3>&2 4>&1)
$ echo "$bar"
foo
$ cat stdout.log
foo
$ cat stderr.log
$ bar=$({
    {
        echo foo >&2 | tee stdout.log 2>&3 3>&-
    } 2>&1 >&4 4>&- | tee stderr.log 2>&3 3>&-
} 3>&2 4>&1)
$ cat stdout.log
$ cat stderr.log
foo
$ echo "$bar"
foo

除了上一次迭代,bar的值被设置为stderr的内容,这似乎是可行的。对所有这些都有什么建议吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-12-21 10:48:37

请看BashFAQ/106。吃你的蛋糕也不容易。

从这一页:

但有些人既不接受stdout和stderr之间的分离,也不接受线的去同步化。他们是纯粹主义者,所以他们要求最困难的形式--我想把stdout和stderr一起记录到一个文件中,但我也希望他们能维护他们原来的、独立的目的地。 为了做到这一点,我们首先要做几点笔记:

  • 如果要有两个独立的stdout和stderr流,那么有些进程必须分别编写它们。
  • 在shell脚本中,如果其中一个有可用的输入,就不可能用shell脚本从两个单独的FDs中读取进程,因为shell没有轮询(2)或select(2)接口。
  • 因此,我们需要两个独立的编写过程。
  • 防止两个独立作者的输出相互破坏的唯一方法是确保它们都以附加模式打开它们的输出。在附加模式下打开的FD具有保证属性,即每次向其写入数据时,它都会跳到末尾。

所以:

代码语言:javascript
复制
# Bash
> mylog
exec > >(tee -a mylog) 2> >(tee -a mylog >&2)

echo A >&2
cat file
echo B >&2

这确保日志文件是正确的。它不能保证编写者在下一个shell提示符之前完成:

代码语言:javascript
复制
~$ ./foo
A
hi mom
B
~$ cat mylog
A
hi mom
B
~$ ./foo
A
hi mom
~$ B

另外,请参见BashFAQ/002BashFAQ/047

票数 11
EN

Stack Overflow用户

发布于 2010-12-21 12:03:02

这听起来像是多人的任务。

要在不使用进程替换的情况下测试同步输出或磁盘写入,您可能需要使用Bash重定向技巧和tee(1),类似于以下内容:

代码语言:javascript
复制
echos() { echo "hello on stdout"; echo "hello on stderr" 1>&2; return 0; }

   { 
  { 
     echos 3>&- | 
        tee stdout.log 2>&3 3>&- 
  } 2>&1 >&4 4>&- | 
        tee  stderr.log 2>&3 3>&- 
} 3>&2 4>&1 2>&1 | tee /dev/stderr > all.log

open -e stdout.log stderr.log all.log   # Mac OS X

有关更多信息,请参见:http://codesnippets.joyent.com/posts/show/8769

要获取该命令的退出代码,您可能希望分别签出pipefail或PIPESTATUS (除了最后一个退出代码变量"$?"):

代码语言:javascript
复制
help set | grep -i pipefail
man bash | less -p pipefail
man bash | less -p PIPESTATUS
票数 2
EN

Stack Overflow用户

发布于 2011-05-11 18:11:52

对于最后一次迭代,其中bar的值设置为stderr的内容,请尝试:

代码语言:javascript
复制
# restore original stdout & stderr at the end by adding: 1>&2 2>&1
bar="$(
{
   {
      echo foo >&2 | tee stdout.log 2>&3 3>&-
   } 2>&1 >&4 4>&- | tee stderr.log 2>&3 3>&-
} 3>&2 4>&1 1>&2 2>&1
)"

echo "$bar"
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4497817

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档