【问题标题】:How to capture stderr and stdout AND timing info with tee including SIGINT?如何使用包括 SIGINT 在内的 tee 捕获 stderr 和 stdout 以及时间信息?
【发布时间】:2018-11-09 17:58:16
【问题描述】:

假设我有一个程序foo 可以同时打印到stderr 和stdout。我希望能够计时并将tee 输出到日志文件。

节目说明

我可以拨打foo如下:

user$ time ./foo

这给出(例如)两个流的输出:

标准输出:

stdout says hi

标准错误:

stderr says hi

结合标准错误和标准输出

我可以使用 BASH I/O 重定向轻松地将它们组合成标准输出:

user$ ./foo 2>&1

这给出了以下输出:

标准输出:

stdout says hi
stderr says hi

stderr:(空!)

使用tee

我可以使用tee捕获程序的组合输出:

user$ ./foo 2>&1 | tee log.txt

标准输出:

stdout says hi
stderr says hi

stderr:(空!)

log.txt:

stdout says hi
stderr says hi

使用time 捕获时间

我可以使用 BASH 的内置 time 命令来计时我的程序的执行同时结合标准输出和标准错误:

user$ time ./foo 2>&1

标准输出:

stdout says hi
stderr says hi

标准错误:

real    0m0.017s
user    0m0.003s
sys     0m0.004s

我可以按照here 的描述捕获time 命令的输出并将其重定向到一个文件:

user$ ( time ./foo ) > log.txt

标准输出:(空!)

标准错误:

stderr says hi

real    0m0.017s
user    0m0.003s
sys     0m0.004s

log.txt: 标准输出打招呼

组合 I/O,捕获 time 的输出,并将管道连接到 tee

如何做到这一点?我在想像下面这样的东西:

( time ./foo 2&>1 ) | tee log.txt

标准输出:(空!)

stdout says hi
stderr says hi

real    0m0.017s
user    0m0.003s
sys     0m0.004s

stderr:(空!)

log.txt:

stdout says hi
stderr says hi

real    0m0.017s
user    0m0.003s
sys     0m0.004s

执行以下工作,除非我 Ctrl-C (SIGINT) 过早退出程序。

( time ./foo ) 2&>1 | tee log.txt

当我也使用 Ctrl-C 时,我怎样才能让它工作?

【问题讨论】:

  • 您的链接建议使用(time ls) &> file,这也适用于您的情况。那么,为什么您忽略了&? (即(time ...) |& tee ...
  • @rici:好建议。使用 GNU bash version 3.2.57(1)-release(我无法在远程计算机上更新 BASH)时,该语法对我不起作用,尽管它确实似乎适用于 GNU bash, version 4.4.19(1)-release(我可以并且已经更新了 BASH) .我会看看我的系统管理员是否可以在远程计算机上更新 BASH,但我仍然对解决方案感兴趣。
  • 顺便说一句,管道到tee 的部分棘手之处在于 ctrl+c 向整个进程组发送了一个 SIGINT —— 所以它同时关闭了tee它会关闭运行time 的子shell,这意味着您无法保证(即它取决于比赛的结果)tee 是否真的能够刷新该shell 的输出。

标签: bash time pipe io-redirection tee


【解决方案1】:
myfunc() { echo stdout; echo stderr >&2; sleep 3; }
{ time myfunc; } > >(tee log.txt) 2>&1

...将内容包括 time 元数据发送到log.txt,即使使用 Ctrl+C 取消也是如此。

请参阅Write tcpdump output to compressed / gziped file 以获得对同一问题的更深入讨论,包括针对脚本而非交互式解释器的答案。


对于您示例中的程序foo,您可以执行以下操作:

{ time ./foo; } > >(tee log.txt) 2>&1

【讨论】:

  • @jvriesem, ...re: 编辑,我希望您可以只使用time ./foo,而不是需要该功能(仅出于可测试目的添加)和time myfunc;不是这样吗?
  • 果然! { time myfunc; } > >(tee log.txt) 2>&1 似乎足够了。谢谢! (编辑了答案。)
最近更新 更多