不使用子shell实现函数stdout/stderr分存与合并日志输出
解决方案
要满足你的需求——在当前shell执行函数、分别保存stdout/stderr到单独日志、同时按原输出顺序合并到combined.log——可以用以下写法:
v=1 fun() { v=2 echo out1 >&2 echo err1 echo out2 >&2 echo err2 } { fun > >(tee out.log) 2> >(tee err.log >&2) } >combined.log
验证效果
执行后:
- 全局变量
v的值变为2,说明函数未在子shell中运行 out.log内容:out1 out2err.log内容:err1 err2combined.log内容(顺序与函数输出完全一致):out1 err1 out2 err2
原理说明
- 避免子shell:整个函数执行逻辑未被包裹在
()或管道左侧(这些会触发子shell),函数直接在当前shell环境运行,因此能修改全局变量v。 - 分流stdout/stderr:
fun > >(tee out.log):将函数的stdout通过tee命令同时写入out.log和当前的stdout流2> >(tee err.log >&2):将函数的stderr通过tee命令同时写入err.log,并通过>&2将复制后的stderr流放回原stderr通道
- 合并输出到combined.log:外层的
{ ... } >combined.log将经过tee处理后的stdout和stderr流合并写入combined.log,由于bash会按输出产生的先后顺序处理流,因此能完美保留原输出顺序。
为什么之前的写法无效
- 初始写法
fun >out.log 2>err.log &>combined.log:bash重定向是从左到右解析的,&>combined.log会覆盖之前的>out.log和2>err.log,导致只有combined.log有内容。 - 你编辑后的嵌套重定向写法:由于stdout和stderr分别通过两个独立的
tee进程处理,不同进程的缓冲机制可能导致输出顺序错乱,无法保证原有的输出时序。
内容的提问来源于stack exchange,提问作者anick
相关产品推荐
相关产品推荐

