如何将stdout和stderr重定向到文件并显示stderr到控制台?


18

我知道如何重定向到文件,并使用tee;在基本水平上。所以

$ 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

问题是:用什么代替问号来获得下面的输出:

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

内容:

  • 假设重击。
  • 订单应保存在文件中。
  • stderr的内容逐行实时显示,即没有缓冲。
  • 可以使用单独的脚本文件。
  • 魔术可能是必要的。

outanderr您对程序有多少控制权?
凯文

1
@Kevin我认为这个问题比这更笼统。在这里,outanderr只是一个别名,它在stdout和stderr上打印一行。这个想法(如果可能)是构建一个通用解决方案,该解决方案可以与任何程序一起使用,而无需修改它们。
lgeorget 2013年

@lgeorget我理解这一点,但我不认为有可能严格满足通用解决方案中的所有限制,因此我在查看是否可以得到特定解决方案。
凯文

@Igeorget是正确的。
TWiStErRob

Answers:


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

为了方便测试:

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

编辑1:

这是通过(仅)将stdout写入文件,使sterr stdout使其通过管道并让tee将其输出写入同一文件来实现的。

两次写入都必须以附加模式(>>而不是>)完成,否则两者都会覆盖彼此的输出。

由于管道是缓冲区,因此不能保证输出以正确的顺序出现在文件中。如果将应用程序连接到两个文件描述符(两个管道),这甚至都不会改变。为了保证顺序,两个输出必须通过同一通道并分别进行标记。否则,您将需要一些真正有趣的东西:

  1. 如果将stdout和stderr都重定向到一个文件(不是同一文件!),并且两个文件都在FUSE卷上,则FUSE模块可以用时间戳标记每个单写操作,以便第二个应用程序可以正确地对数据进行排序并将其合并用于实际的输出文件。或者,您不标记数据,而是让模块创建组合的输出文件。很可能还没有FUSE模块可以执行此操作...
  2. stdout和stderr都可以定向到/dev/null。通过运行该应用程序,可以将其输出分开strace -f -s 32000 -e trace=write。在这种情况下,您将不得不转义。不用说,通过跟踪应用程序不会运行得更快。
  3. 通过使用现有的简单FUSE模块并跟踪该模块而不是应用程序,也许可以达到相同的目的。这可能比跟踪应用程序更快,因为(或更确切地说:如果)该模块的系统调用可能比应用程序少得多。
  4. 如果可以修改应用程序本身:可以在每次输出后停止该应用程序(但我认为这只能从内部进行),并且仅在收到s信号(SIGUSR1或SIGCONT)后才能继续。从管道读取的应用程序必须检查管道和文件中是否有新数据,并在每个新数据之后发送信号。根据应用程序的类型,它可能比strace方法更快或更慢。FUSE将是最高速度的解决方案。

1
呸。在撰写完全相同的答案为什么不聊天的过程中抓住我。
凯文2013年

2
注意,这有一个竞争条件,引入了换出/错误线路的可能性,但我认为这是无法避免的。
凯文

1
@Kevin这对我们最好的人来说是正确的,我以前曾遭受过这种痛苦,并且几乎要求“向我展示有人在写”功能(尽管这很复杂)。在我看来,竞争条件仅在写入管道之后发生对文件(stdout)的写入时才会发生。
Hauke Laging 2013年

会不会同时发送stdoutstderrtee,或者我错过了什么?我认为OP的要求tee stderr仅为。
2013年

@JosephR。您不是碰巧尝试过的吗?
Hauke Laging
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.