Shell重定向之`>/dev/null 2>&1`
在看 shell 脚本时,经常会看到这样一段写法:
command >/dev/null 2>&1 |
很多人第一次看到会觉得有点绕,尤其是 2>&1 这部分,不太容易一眼看明白。
这篇文章就专门整理一下它的含义,以及为什么顺序不能乱写。
一、这段写法到底是什么意思
command >/dev/null 2>&1 |
它表示:
- 把标准输出重定向到
/dev/null - 再把标准错误重定向到标准输出当前所在的位置
最终效果就是:
正常输出和报错输出都会被丢弃,不在终端显示。
二、先理解 3 个标准通道
在 Unix/Linux 里,一个进程默认会带有 3 个标准通道,对应 3 个文件描述符:
0 = stdin |
分别表示:
0:标准输入,程序从哪里读数据1:标准输出,程序正常结果输出到哪里2:标准错误,程序报错信息输出到哪里
后面提到的 1>、2>、2>&1,本质上都是在操作这些文件描述符。
三、>/dev/null 是什么意思
command >/dev/null |
它等价于:
command 1>/dev/null |
意思是把标准输出重定向到 /dev/null。
这里有两个点:
>表示输出重定向/dev/null是一个特殊设备文件,写进去的内容会被直接丢弃
所以这条命令的效果是:
- 正常输出不再显示
- 错误输出仍然会显示在终端
例如:
ls existing-file missing-file >/dev/null |
这时 existing-file 的正常输出会被丢弃,但如果 missing-file 不存在,报错信息还是会显示出来。
四、2>&1 是什么意思
2>&1 |
它的含义是:
把标准错误重定向到文件描述符 1 当前所指向的位置。
拆开看会更清楚:
2>:操作标准错误&1:表示引用文件描述符1
注意这里的 1 不是文件名,而是文件描述符编号。
也就是说:
command >/dev/null 2>&1 |
可以理解成:
- 先把标准输出丢到
/dev/null - 再让标准错误也跟着标准输出走
所以最后标准输出和标准错误都会进入 /dev/null。
五、为什么 1 前面要加 &
因为 shell 需要区分:
- 你写的是文件描述符
- 还是普通文件名
不加 &
command 2>1 |
这表示把标准错误写入一个名为 1 的文件。
加上 &
command 2>&1 |
这表示把标准错误重定向到文件描述符 1。
所以 & 的作用很简单,就是告诉 shell:
后面的数字不是文件名,而是文件描述符。
六、为什么 1 可以省略
在 shell 里:
>file |
默认就是:
1>file |
因为如果 > 前面没有写编号,默认操作的就是标准输出。
所以:
>/dev/null |
等价于:
1>/dev/null |
七、顺序为什么很重要
很多人会把下面两种写法看成一样,其实它们不一样。
写法 A
command >/dev/null 2>&1 |
执行顺序是:
- 让
1指向/dev/null - 让
2指向1当前的位置,也就是/dev/null
结果:
- 标准输出被丢弃
- 标准错误也被丢弃
写法 B
command 2>&1 >/dev/null |
执行顺序是:
- 先让
2指向1当前的位置,此时1还是终端 - 再把
1重定向到/dev/null
结果:
- 标准输出被丢弃
- 标准错误仍然输出到终端
所以这两条命令不是一回事:
command >/dev/null 2>&1 |
重点就在于 shell 会从左到右依次处理重定向。
八、常见用法
1. 只隐藏正常输出
command >/dev/null |
2. 只隐藏错误输出
command 2>/dev/null |
3. 同时隐藏正常输出和错误输出
command >/dev/null 2>&1 |
4. 正常输出和错误输出都写入同一个文件
command >all.log 2>&1 |
5. 正常输出写文件,错误仍然显示在终端
command >out.log |
6. 错误写文件,正常输出仍然显示在终端
command 2>err.log |
九、/dev/null 是什么
/dev/null 是 Unix/Linux 下的一个特殊设备文件,常被叫做“黑洞设备”。
它的特点很简单:
- 写进去的内容会被丢弃
- 从里面通常读不到有意义的内容
所以它特别适合拿来做静默执行,比如:
- 不想看到命令的普通输出
- 不想让脚本打印一堆无关信息
- 想让某些命令安静执行
十、实际例子
比如在脚本里,你可能会看到:
source venv/bin/activate >/dev/null 2>&1 |
它表示:
- 执行
venv/bin/activate - 不显示正常输出
- 不显示错误输出
不过这里也要注意一件事:
如果激活失败,报错信息也会被隐藏掉。
所以在排查问题时,通常要先把这类重定向去掉,不然看不到真实报错。
十一、还有一种更简写的写法
在 bash 和 zsh 里,经常还能看到:
command &>/dev/null |
它通常等价于:
command >/dev/null 2>&1 |
不过如果考虑可读性和兼容性,很多时候还是传统写法更直观一些:
command >/dev/null 2>&1 |
十二、小结
>/dev/null 2>&1 本质上就是 shell 重定向语法。
它的含义可以概括成一句话:
先把标准输出重定向到 /dev/null,再把标准错误重定向到标准输出当前所在的位置,从而让正常输出和错误输出都被丢弃。
如果只想记住最关键的几条,可以直接记下面这个速记版:
0 = stdin |
>/dev/null # 等价于 1>/dev/null,隐藏标准输出 |
2>1 # 写入名为 1 的文件 |
参考文章