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

如何在sh中实现stdout和stderr接入tee且保留独立输出流

解决方案

POSIX 标准 sh 不支持 bash 特有的进程替换(>()语法)和&>合并重定向简写,要满足保留原命令退出码、不合并stdout/stderr流、同时复制两路输出到tee目标文件的需求,可以通过命名管道(FIFO)实现。

可直接运行的等价代码

#!/bin/sh

# -------------------------- 第一条gcc命令 --------------------------
# 创建临时命名管道用于传递输出
fifo=$(mktemp -u)
mkfifo "$fifo"
# 后台启动tee,将所有收到的输出覆盖写入toto.txt
tee toto.txt < "$fifo" >/dev/null &
tee_pid=$!

# 执行gcc命令,stdout和stderr同时输出到原流和管道
{
  { gcc; echo $? > ".gcc_ret.$$"; } 2>&1 >&3 | tee -a "$fifo" >&2
} 3>&1 | tee -a "$fifo"
# 捕获gcc的退出码
gcc_ret=$(cat ".gcc_ret.$$")
rm -f ".gcc_ret.$$"
# 等待tee写入完成后清理临时管道
wait $tee_pid
rm -f "$fifo"

# 后续条件判断逻辑和原bash版本完全一致
[ "$gcc_ret" -eq 0 ] && echo 'ok' || echo 'oups'

# -------------------------- 第二条gcc命令 --------------------------
# 新建临时管道用于追加写入
fifo=$(mktemp -u)
mkfifo "$fifo"
# tee改为追加模式写入toto.txt
tee -a toto.txt < "$fifo" >/dev/null &
tee_pid=$!

{
  { gcc --version; echo $? > ".gcc_ret.$$"; } 2>&1 >&3 | tee -a "$fifo" >&2
} 3>&1 | tee -a "$fifo"
gcc_ret=$(cat ".gcc_ret.$$")
rm -f ".gcc_ret.$$"
wait $tee_pid
rm -f "$fifo"

[ "$gcc_ret" -eq 0 ] && echo 'ok' || echo 'oups'

方案特性

  • 完全兼容POSIX sh标准,不依赖bash专属语法
  • 原命令的stdout和stderr保持独立流属性,不会合并,stdout仍流向标准输出、stderr仍流向标准错误
  • 原命令的退出码完全保留,后续的条件判断逻辑和原bash版本行为一致
  • 两路输出都会同步复制一份写入tee指定的文件,效果和原bash实现完全一致

内容的提问来源于stack exchange,提问作者R. N

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 23:00:02