shell重定向知多少
一、Linux 三个标准流
Linux 进程启动时默认打开 3 个文件描述符(FD):
示意:
stdin (0) ← keyboard
stdout (1) → terminal
stderr (2) → terminal
二、重定向的本质
重定向本质:改变文件描述符指向的目标。
例如:
ls > file.txt
等价于:
stdout (1) → file.txt
stderr (2) → terminal
三、最常用的重定向符号
1 输出重定向
覆盖
command > file
效果:
stdout → file
文件存在会 清空并覆盖
追加
command >> file
效果:
stdout → file (append)
2 错误重定向
command 2> file
效果:
stderr → file
追加:
command 2>> file
3 输入重定向
command < file
效果:
stdin ← file
例如:
wc -l < file.txt
四、同时重定向 stdout 和 stderr
标准写法(最常见)
command > file 2>&1
最终:
stdout → file
stderr → file
bash 简写
command &> file
等价:
command > file 2>&1
追加:
command &>> file
五、2>&1 的真正含义
2>&1
意思是:
stderr → stdout 当前指向的位置
注意:
不是指向 stdout
而是复制 stdout 的目标
六、Shell 重定向执行顺序
规则:
Shell 从左到右解析重定向
并在命令执行前全部完成
七、经典案例分析
情况1(正确)
command > file 2>&1
执行步骤:
第一步
stdout → file
第二步
stderr → stdout 当前的位置 (file)
最终:
stdout → file
stderr → file
情况2(顺序不同)
command 2>&1 > file
执行步骤:
第一步
stderr → stdout (terminal)
第二步
stdout → file
最终:
stdout → file
stderr → terminal
八、一个重要理解
很多人误以为是 数据流路径
例如:
stderr → stdout → file
实际上 不是这样。
正确理解:
文件描述符复制
例如:
初始:
fd1 → terminal
fd2 → terminal
执行:
2>&1
变成
fd2 → terminal
然后
>file
变成
fd1 → file
fd2 → terminal
九、丢弃输出
Linux 有一个特殊设备:
/dev/null
表示 黑洞设备。
丢弃 stdout
command > /dev/null
丢弃 stderr
command 2> /dev/null
丢弃所有输出
command > /dev/null 2>&1
十、管道(另一种重定向)
command1 | command2
含义:
command1 stdout → command2 stdin
例如:
ls | grep txt
十一、Here Document
多行输入:
cat << EOF
hello
linux
EOF
输出:
hello
linux
十二、Here String
grep hello <<< "hello world"
十三、自定义文件描述符
可以自己创建 fd。
例如:
exec 3> file.txt
此时
fd3 → file.txt
写入:
echo hello >&3
关闭:
exec 3>&-
十四、底层原理(Linux 系统调用)
Shell 实际做的是:
dup2()
open()
execve()
例如:
command > file 2>&1
类似:
open(file)
dup2(file,1)
dup2(1,2)
exec(command)
十五、最核心的 3 条规则(必须记住)
规则1
重定向本质是修改文件描述符
规则2
Shell 从左到右解析重定向
规则3
>&N 表示复制文件描述符 N 当前指向的位置
十六、面试高频问题
问
command >file 2>&1
和
command 2>&1 >file
区别?
答:
前者:stdout stderr 都到 file
后者:stdout 到 file,stderr 到终端
问
2>&1 是什么意思
答:
stderr 指向 stdout 当前指向的位置
十七、一张终极图
默认
stdin (0) ← keyboard
stdout (1) → terminal
stderr (2) → terminal
执行:
command >file 2>&1
变成
stdout → file
stderr → file
十八、一句口诀(非常好记)
重定向改 FD
解析从左到右
>&N 复制目标
Linux Shell 重定向体系图
Linux Shell IO
│
┌─────────────────┼─────────────────┐
│ │ │
stdin stdout stderr
(fd 0) (fd 1) (fd 2)
│ │ │
│ │ │
输入重定向 输出重定向 错误重定向
│ │ │
< file > file 2> file
>> file 2>> file
│
│
┌─────────┴─────────┐
│ │
stdout+stderr 丢弃输出
│ │
>file 2>&1 /dev/null
&> file > /dev/null
2> /dev/null
> /dev/null 2>&1
文件描述符关系图
默认状态:
stdin (0) ← keyboard
stdout(1) → terminal
stderr(2) → terminal
重定向示例
command > file
stdout (1) ─────────► file
stderr (2) ─────────► terminal
command 2> file
stdout (1) ─────────► terminal
stderr (2) ─────────► file
command > file 2>&1
stdout (1) ─┐
├────────► file
stderr (2) ─┘
command 2>&1 > file
stdout (1) ─────────► file
stderr (2) ─────────► terminal
原因:重定向从左到右解析
管道结构图
command1 command2
│ │
│ stdout │ stdin
└─────── pipe ─────┘
例子:
ls | grep txt
ls stdout ───► grep stdin
文件描述符复制图(2>&1)
初始:
fd1 ───► terminal
fd2 ───► terminal
执行:
2>&1
变成:
fd1 ───► terminal
fd2 ───► terminal (复制fd1目标)
/dev/null 黑洞
command ───► /dev/null
效果:
stdout 丢弃
stderr 丢弃
完整 IO 数据流图
keyboard
│
▼
stdin(0)
│
▼
command
┌─────┴─────┐
│ │
stdout(1) stderr(2)
│ │
│ │
file / pipe file / terminal
Shell 重定向核心三条规则
1. 重定向本质:修改文件描述符指向
2. Shell 从左到右解析重定向
3. >&N 表示复制文件描述符N当前指向的位置
Shell 解析命令
│
▼
command > file 2>&1
│
▼
┌──────────────────────────┐
│ 1. 打开 file.txt │
│ open("file.txt") │
│ 得到 fd = 3 │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ 2. dup2(3, 1) │
│ │
│ 把 fd3 复制到 fd1 │
│ │
│ stdout → file.txt │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ 3. dup2(1, 2) │
│ │
│ 把 fd1 复制到 fd2 │
│ │
│ stderr → file.txt │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ 4. execve(command) │
│ │
│ 启动程序 │
└──────────────────────────┘
│
▼
command 运行
│
┌───────────┴───────────┐
│ │
stdout stderr
│ │
└──────────► file.txt ◄─┘
许可协议:
CC BY 4.0