Linux Shell中管道只传递stdout,stderr默认不进管道;需用2>&1将stderr合并到stdout才能被grep捕获;&>log是原子操作,而>out.log 2>&1分步执行;tee可同时保存日志并实时筛选;分离输出时用(cmd 2>err.log) >out.log保证时序。

Linux Shell 中的管道和重定向不是两个独立技巧,而是协同工作的数据流控制机制。真正用好它们的关键,在于理解标准流(stdin/stdout/stderr)的流向如何被动态修改,以及何时必须按特定顺序组合操作。
管道只传 stdout,stderr 默认“掉队”
管道符 | 本质是把前一个命令的文件描述符 1(stdout)连到后一个命令的文件描述符 0(stdin)。它完全不碰文件描述符 2(stderr)——错误信息仍直接输出到终端,不会自动进管道。
- 想让 grep 捕获错误?必须先让 stderr 流向 stdout,再建管道: cmd 2>&1 | grep "error"
- 写成 cmd | grep "error" 2>&1 是错的:此时管道已建立,2>&1 只是把 stderr 指向终端的 stdout,没进管道
- cmd 2>1 | grep 更危险:这不是重定向到描述符 1,而是创建一个叫 “1” 的普通文件
合并输出与错误的两种常用写法
>& 和 2>&1 效果相似但行为不同:
- cmd >&log 是语法糖,等价于 cmd >log 2>&1,原子完成,要么全成功,要么全失败
- cmd >out.log 2>&1 分两步:若 out.log 不可写,stdout 重定向失败,但 stderr 仍可能输出到终端
- cmd 2>&1 >out.log 顺序反了:先将 stderr 指向终端 stdout,再改 stdout 到文件,错误依然打屏
一边存日志、一边实时筛选:用 tee 拆流
当需要同时保存完整输出并实时过滤关键行时,tee 是核心工具:
- make 2>&1 | tee build.log | grep -E "(ERROR|FAIL)":全量内容写入 build.log,匹配行实时刷屏
- 加 -i 忽略大小写:| grep -i "warning"
- 防 Broken pipe(如 head 提前退出):cmd 2>&1 | head -n 5 2>/dev/null,或更健壮写法:cmd 2>&1 | { head -n 5 || true; }
分离 stdout 与 stderr 到不同文件(保持时序)
直接重定向无法保证时序一致(因两个流异步写入),稳妥做法是用子 shell 隔离:
- (cmd 2>err.log) >out.log:stderr 单独进 err.log,stdout 进 out.log
- 若需保留时序且合并查看,建议先全量捕获:cmd 2>&1 >full.log,再用 awk/grep 分析


















