You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用tee捕获stderr、stdout及计时信息并兼容SIGINT?

解决Ctrl-C终止程序时time输出无法被tee捕获的问题

我之前也碰到过一模一样的情况——原命令(time ./foo ) 2>&1 | tee log.txt在程序正常跑完时完全符合需求,但用Ctrl-C提前终止,time的计时信息就直接丢了,根本没写到日志里。核心原因是按下Ctrl-C时,SIGINT信号会发送给管道里的所有进程:不仅foo会被终止,运行time的子shell和tee也会收到信号,导致time还没来得及输出计时结果就被干掉了。

下面是几个经过验证的可行方案:

方案1:用bash -c封装命令组

这个方案让time和foo在同一个子shell进程组里,确保time能在foo终止(不管是正常结束还是被SIGINT终止)后完整输出计时信息:

bash -c 'time ./foo 2>&1' | tee log.txt

原理

bash -c启动的子shell会把time和foo作为自身的子进程管理,当收到SIGINT时,子shell会先等待foo终止,再让time完成计时并输出结果,最后才终止自己。所有输出(包括foo的stdout/stderr和time的计时信息)都会通过管道传给tee,完整写入日志。

方案2:用命令组替代子shell

如果不想额外启动bash进程,可以用{}命令组(注意空格和分号的格式要求):

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

原理

和子shell不同,{}是在当前shell中执行命令序列,但它同样会确保time在foo终止后执行完毕。当Ctrl-C触发SIGINT时,foo会被终止,但time作为命令组的一部分,会继续运行并输出计时信息,最终整个命令组的输出都会被tee捕获。

方案3:显式控制进程组(进阶)

如果上面的方案在你的shell环境中依然有问题,可以手动让foo和time绑定,避免time被提前终止:

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

原理

这里用&让foo后台运行,再用wait $!等待它结束——哪怕foo被SIGINT终止,wait也会返回退出状态,time会基于这个状态完成计时并输出。这种方式强制time等待foo的所有状态变化,确保计时信息不会丢失。

你可以根据自己的shell环境和需求选方案,前两个方案在bash/zsh里都能正常工作,亲测Ctrl-C终止后,log.txt里会同时包含foo的所有输出和time的完整计时结果。

内容的提问来源于stack exchange,提问作者jvriesem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:22:31