Linux Shell重定向本质是修改进程文件描述符(fd 0/1/2)指向,控制输入输出目标;fd 0默认键盘输入,fd 1/2默认终端输出,重定向通过dup2()等系统调用实现指向替换。

Linux Shell 重定向的本质,是通过修改进程的文件描述符(file descriptor)指向,来控制命令的输入来源和输出去向。标准输入(stdin,fd 0)、标准输出(stdout,fd 1)、标准错误(stderr,fd 2)默认连接到终端,而重定向操作就是让它们指向文件、管道、其他命令或 /dev/null 等特殊目标。
文件描述符是重定向的操作对象
Shell 启动命令时,会为每个进程预先打开三个文件描述符:
-
0(stdin):默认读取键盘输入,可被
<或<<重定向为从文件或 here-document 读取 -
1(stdout):默认输出到终端,可被
>或>>重定向到文件(覆盖或追加) -
2(stderr):默认也输出到终端,但独立于 stdout,可用
2>单独重定向
重定向符号实际调用的是系统调用(如 dup2()),把某个 fd 的指向替换成另一个打开的文件或设备。
常见重定向写法背后的含义
看似简单的符号,对应明确的文件描述符操作逻辑:
-
cmd > out.txt:将 fd 1 指向out.txt(先截断再写入) -
cmd >> out.txt:将 fd 1 指向out.txt,以追加模式打开 -
cmd 2>&1:把 fd 2 复制为 fd 1 当前指向的位置(即让 stderr 和 stdout 输出到同一目标) -
cmd > out.txt 2>&1:先重定向 stdout 到文件,再让 stderr 跟随 stdout —— 常见的“合并输出”写法 -
cmd < in.txt:将 fd 0 指向in.txt,命令从此文件读取输入
注意:>& 和 >& 是等价的(Bash 中 & 在重定向中表示“复制文件描述符”,不是后台运行)。
重定向与管道的本质区别
管道(|)不是重定向,而是进程间通信机制:
- 管道自动创建一对连接的文件描述符(一端写、一端读),并让前一个命令的 stdout(fd 1)指向写端,后一个命令的 stdin(fd 0)指向读端
- 它不涉及磁盘文件,数据在内核缓冲区中流动,实时性强
- 而重定向多数面向持久化目标(如文件),也可指向
/dev/stdout等伪设备实现类似效果,但语义和实现路径不同
例如:ls | grep txt 是两个进程通过内存管道连接;ls > file && grep txt file 是两次独立执行,中间依赖磁盘文件中转。
错误流分离与调试技巧
stderr 默认不被 > 影响,这是设计关键:
- 即使
cmd > out.txt,报错信息仍打印到终端,避免掩盖问题 - 想静默错误?用
cmd 2> /dev/null - 想分别保存正常输出和错误?
cmd > out.txt 2> err.txt - 想统一分析所有输出?
cmd > all.txt 2>&1(注意顺序:先设置 stdout,再让 stderr 跟它)
误写成 cmd 2>&1 > out.txt 会导致 stderr 仍输出到终端 —— 因为 2>&1 发生时,fd 1 还指向终端,之后 > out.txt 只改变 fd 1,不影响已复制的 fd 2。









