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

如何在/bin/sh中分别过滤STDOUT与STDERR且保留原输出流?

在/bin/sh中独立过滤STDOUT与STDERR的无临时文件实现方案

需求背景

需要实现对程序的STDOUT和STDERR分别进行过滤,且不合并两者的输出,流程如下:

STDOUT ── [ filter ] ────> STDOUT
                       
STDERR ── [ filter ] ────> STDERR

同时需满足以下要求:

  • 保留原程序的$?退出返回值
  • 允许原程序(如myprogram函数)修改当前shell的环境变量
  • 不能使用临时文件或命名管道,仅通过exec重定向实现
  • 适配标准/bin/sh(Bash特有的>(cmd)进程替换构造无法使用)

可行实现方案

可以通过文件描述符备份+子shell分流的纯POSIX兼容写法实现,完全无需磁盘存储,适用于只读文件系统。

具体代码示例

#!/bin/sh

# 自定义过滤逻辑,这里以给每行添加前缀为例,可替换为实际需求
filter() {
    sed 's/^/[PROCESSED] /'
}

# 备份当前shell的标准输出、标准错误到文件描述符3、4
exec 3>&1 4>&2

# 执行目标程序并分别过滤输出
# 核心逻辑:通过子shell分流STDOUT和STDERR,各自过滤后回写到原终端流
( myprogram 2>&1 >&3 | filter >&4 ) 3>&1 | filter
# 捕获原程序的退出码
program_exit=$?

# 释放备份的文件描述符
exec 3>&- 4>&-

# 示例:使用原程序的退出码
echo "原程序退出状态: $program_exit"

原理说明

  1. 文件描述符备份:exec 3>&1 4>&2将当前shell的STDOUT(fd1)和STDERR(fd2)复制到fd3和fd4,确保后续能将过滤后的内容输出回原终端。
  2. 分流与过滤:
    • 内层子shell中,myprogram 2>&1 >&3把原程序的STDERR重定向到自身STDOUT,同时将原程序的STDOUT直接写入备份的fd3(即原终端的STDOUT)。
    • 内层子shell的STDOUT(包含原程序的STDERR)通过管道传给filter,处理后写入备份的fd4(原终端的STDERR)。
    • 外层管道接收来自fd3的原程序STDOUT内容,经过filter处理后输出到原终端的STDOUT。
  3. 退出码保留:myprogram执行完成后,其退出码可直接通过$?捕获,因为子shell的退出状态会传递到当前shell。
  4. 环境变量修改支持:如果myprogram是当前shell定义的函数,或者是在当前shell环境中执行的命令,其对环境变量的修改会保留在当前shell中(外部命令本身无法修改父shell环境变量,这是shell的固有特性)。

注意事项

  • 该方案完全符合POSIX标准,可在任何兼容/bin/sh的环境中运行。
  • 过滤函数filter可以替换为任何能读取标准输入、输出到标准输出的命令或脚本,适配各种处理需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:52:42