Shell中标准输入输出重定向与管道符可嵌套组合使用;进程默认有stdin(0)、stdout(1)、stderr(2)三类标准流,重定向本质是改变文件描述符指向;>等价于1>,2>单独重定向stderr,&>合并stdout和stderr,2>&1|grep可捕获错误做文本处理;管道仅传递stdout,需显式重定向stderr才能入管道;括号分组支持对多命令统一重定向。

Shell 中标准输入输出重定向与管道符不是互斥操作,而是可以灵活嵌套、组合使用的强大机制。掌握它们的协同逻辑,才能真正写出健壮、可维护的命令行脚本。
理解三类标准流与重定向本质
每个进程默认拥有三个标准流:stdin(0)、stdout(1)、stderr(2)。重定向的本质是改变这些文件描述符指向的目标(文件、设备或另一个流),而非简单“把内容塞进文件”。
- > file 等价于 1> file,只重定向 stdout
- 2> err.log 单独重定向 stderr,不影响 stdout 输出位置
- &> all.log 是 1> all.log 2>&1 的简写,将 stdout 和 stderr 合并写入同一文件
- 2>&1 | grep "error" 表示先合并错误流到标准输出,再通过管道交给 grep —— 这是捕获错误信息做文本处理的关键写法
管道与重定向混合使用的常见模式
管道 | 本质是把前一个命令的 stdout 连接到后一个命令的 stdin。它本身不接管 stderr,因此需显式重定向才能让错误也进入管道。
- 想搜索命令执行中的错误关键词:command 2>&1 | grep -i "fail\|error"
- 只保留错误、丢弃正常输出:command > /dev/null 2>&1 | grep . 或更清晰地写成 command 2>&1 >/dev/null | grep .
- 同时保存日志并实时监控关键行:command 2>&1 | tee build.log | grep -E "(SUCCESS|FAILED)"
- 避免管道中断导致的“Broken pipe”报错(如 head 提前退出):command 2>&1 | head -5 2>/dev/null
用括号分组实现复杂流向控制
单条命令的重定向作用范围有限,而用 ( ) 将多个命令分组后,可对整个组统一重定向,大幅提升表达能力。
- 把一组命令的全部输出(含错误)存入日志:(cmd1; cmd2; cmd3) &> run.log
- 仅捕获子 shell 中的错误并报警,正常输出仍显示在终端:(这里用了进程替换,属于进阶技巧)
- 分离 stdout 与 stderr 到不同文件,且保持时序一致(避免竞态):(cmd 2>err.log) >out.log
实战避坑:顺序、优先级与常见误解
Shell 解析重定向是从左到右,且重定向优先级高于管道。错误的书写顺序会导致意料之外的行为。
- cmd >file | grep "ok" ❌ 实际效果是:stdout 写入 file,没有数据进管道;grep 读取的是空输入
- cmd 2>&1 | grep "ok" ✅ 先让 stderr 指向当前 stdout(即终端),再建立管道 —— 此时 stdout 已被管道接管,所以 stderr 也进了管道
- cmd | grep "ok" >result.txt ✅ 管道之后的重定向作用于 grep 的 stdout,结果写入 result.txt
- 调试技巧:用 set -x 查看 Shell 展开后的实际执行命令,比凭经验猜测更可靠










