在 Linux 的世界里,”一切皆文件”是核心哲学。重定向和管道正是这一哲学的最佳体现——它们让命令之间能够自由沟通、协作,将简单命令组合成强大的工作流。
很多初学者觉得重定向和管道难以理解,是因为没有搞清楚 Linux 是如何管理”输入”和”输出”的。本文将从最基础的文件描述符讲起,逐步带你掌握输出重定向、输入重定向、管道、tee、xargs 等核心工具,帮你打通 Linux 命令组合的任督二脉。
请思考
在深入重定向之前,让我们先思考一个问题:
如何让命令的输出持久保存?
- 比如
date命令输出的时间,关机重启后还能查看吗? - 答案当然是不能,因为输出只是显示在屏幕上,并没有保存下来
- 解决办法:使用重定向
date > date.txt,把输出保存到文件中
文件描述符 FD
什么是文件描述符?
文件描述符(File Descriptors,简称 FD),也叫文件句柄。进程使用文件描述符来管理打开的文件。
举个简单例子说明:
想象你在图书馆借书:
- 图书馆(操作系统)有很多书(文件)
- 你不能直接去书架上拿书,而是需要通过借书卡(文件描述符)来获取书籍
- 借书卡上的编号就是 FD,通过这个编号你才能读取或写入文件
标准输入、标准输出、标准错误
每个 Linux 进程启动时,系统会自动为它分配三个特殊的文件描述符:

| FD 编号 | 名称 | 英文全称 | 默认设备 | 读写权限 |
|---|---|---|---|---|
| 0 | 标准输入 | Standard Input (stdin) | 键盘 | 只读 |
| 1 | 标准输出 | Standard Output (stdout) | 屏幕 | 只写 |
| 2 | 标准错误 | Standard Error (stderr) | 屏幕 | 只写 |
| 3+ | 其他文件 | – | 文件 | 读写 |
观察 FD 信息
通过我们非常熟悉的 VIM 程序,来观察一个进程的 FD 信息。
步骤 1:打开一个文本文件
vim 1.txt
步骤 2:在另一个终端查询 vim 的进程号
ps aux | grep vim
输出示例:
root 9069 0.1 0.5 151532 5040 pts/0 S+ 09:21 0:00 vim 1.txt
步骤 3:查看该进程的 FD 信息
通常在 /proc/PID/fd 就能看到文件的FD调用情况。
ls /proc/9069/fd
普通的 ls 可能看不出什么,加上 -l 参数试试:
ll /proc/9069/fd
输出示例:
总用量 0
lrwx------. 1 root root 64 5月 13 09:22 0 -> /dev/pts/0 # 标准输入
lrwx------. 1 root root 64 5月 13 09:22 1 -> /dev/pts/0 # 标准输出
lrwx------. 1 root root 64 5月 13 09:21 2 -> /dev/pts/0 # 标准错误输出
lrwx------. 1 root root 64 5月 13 09:22 3 -> /root/.1.txt.swp # 常规文件(vim 的交换文件)
分析:
0、1、2都指向/dev/pts/0(终端设备)3指向/root/.1.txt.swp(vim 编辑文件时自动创建的临时交换文件)
总结:看到的
0、1、2、3就是文件描述符(FD)。程序通过描述符访问文件,可以是常规文件,也可以是设备文件。FD 就像是进程的”借书卡”,通过它来读取或写入数据。
输出重定向
简介
输出重定向就是把命令的输出结果从屏幕上转移到文件中。
打个比方:
正常情况下,命令的输出会”显示”在屏幕上(标准输出)。输出重定向就像给命令的输出换了个方向——不再显示在屏幕上,而是”写入”到一个文件中。
输出重定向的类型
输出分为正确输出(标准输出)和错误输出(标准错误):
| 类型 | 完整写法 | 简写 | 说明 | 示例 |
|---|---|---|---|---|
| 正确输出 – 覆盖 | 1> | > | 覆盖写入,如果文件已存在则清空后重新写入 | date > date.txt |
| 正确输出 – 追加 | 1>> | >> | 追加写入,在文件末尾添加内容 | date >> date.txt |
| 错误输出 – 覆盖 | 2> | 无简写 | 仅将错误信息重定向到文件 | ls /aaa 2> error.txt |
| 错误输出 – 追加 | 2>> | 无简写 | 将错误信息追加到文件末尾 | ls /aaa 2>> error.txt |
记忆技巧:
>一个箭头表示覆盖(就像新来的把原来的替换掉)>>两个箭头表示追加(新来的跟在后面)
案例 1:正确输出重定向

覆盖写入:
[root@localhost ~]# date 1> date.txt
追加写入:
[root@localhost ~]# date >> date.txt
检验效果:
[root@localhost ~]# cat date.txt
2026年 05月 13日 星期三 09:53:09 CST
2026年 05月 13日 星期三 09:54:42 CST
# 再次覆盖写入
[root@localhost ~]# date > date.txt
[root@localhost ~]# cat date.txt
2026年 05月 13日 星期三 09:55:12 CST
注意:任何程序都可以使用重定向!比如
mkdir -v /test > mkdir.log,只要程序本身有输出,就可以重定向。
案例 2:错误输出重定向

错误示范:
[root@localhost ~]# ls /home/ 2> list.txt
打开 list.txt 会发现没有任何内容,因为 ls /home/ 是一个正确的命令,没有产生错误信息。
正确示范:
[root@localhost ~]# ls /aaaaaaaaa 2> list.txt
[root@localhost ~]# cat list.txt
ls: 无法访问/aaaaaaaaa: 没有那个文件或目录
关键点:当某条命令产生错误时,才会有错误输出。错误输出重定向就是把这些”报错信息”从屏幕上转移到文件中。
案例 3:正确和错误都输入到相同位置

[root@localhost ~]# ls /home/ /aaaaaaaaa &> list.txt
&> 是 bash 的快捷写法,等价于 > file 2>&1,表示正确输出和错误输出都写入到同一个文件(这里的&1指的就是file这个文件,这里做个了解就行)。
生产环境实战:屏蔽所有输出
[root@localhost ~]# yum install httpd &>/dev/null
什么是
/dev/null?
/dev/null是 Linux 系统中的一个特殊设备文件,被称为黑洞。任何写入它的数据都会被丢弃,读取它什么也得不到。当你不关心命令的输出时(比如自动化脚本中),可以把输出重定向到
/dev/null,避免产生大量日志文件。
输入重定向
简介
输入重定向
<(等价于0<):把一个文件的内容作为命令的输入,代替手动键盘输入。
打个比方:
正常使用邮箱发送邮件时,你需要一行一行地输入邮件内容。如果已经有了现成的邮件内容文件,输入重定向就像”把文件内容喂给邮箱”,代替你手动输入。
用 cat 命令读取文件
cat 命令的默认行为是从标准输入(键盘)读取内容并打印到屏幕。输入重定向可以让它从文件读取内容。
步骤 1:不用重定向(从键盘输入)
cat
运行后光标会停在终端,你输入什么,它就会立刻打印什么。按
Ctrl+D结束输入。
步骤2:用输入重定向(从文件读取)
# 先创建一个测试文件
echo "第一行内容" > test.txt
echo "第二行内容" >> test.txt
echo "第三行内容" >> test.txt
# 输入重定向:让cat从test.txt读取输入
cat < test.txt
运行结果:
第一行内容
第二行内容
第三行内容
原理:
< test.txt把标准输入(fd 0)从键盘重定向到文件test.txtcat命令本身没有任何变化,它还是从 “标准输入” 读数据,只是这个 “标准输入” 现在指向了文件
管道
管道 |
简介
管道命令:将多条命令组合起来,一次性完成复杂的处理任务。
语法:
command1 | command2 | command3 | ...

形象理解:
管道就像一根水管:
- 命令 1 的输出 = 水龙头流出的水
- 管道
|= 水管 - 命令 2 的输入 = 水管另一端接收的水
命令 1 的标准输出作为命令 2 的标准输入,形成一个数据流转的链条。
案例
# 查看 /etc/passwd 文件的最后 3 行
[root@localhost ~]# cat /etc/passwd | tail -3
# 查找 sshd 相关的进程
[root@localhost ~]# ps aux | grep 'sshd'
分步拆解:
- 第一步:
cat /etc/passwd- 作用:把
/etc/passwd这个文件的全部内容(系统里所有用户的信息)全部 “倒出来”
- 作用:把
- 第二步:
|(管道)- 作用:把左边命令输出的所有内容,原封不动地通过 “水管” 传给右边的命令
- 第三步:
tail -3- 作用:只接收水管流过来的内容,然后只保留最后 3 行,其他全部扔掉
最终效果:不用打开整个文件翻到最后,一步直接看到系统用户文件的最后 3 行。
第二个示例也是同理,ps aux会静态显示所有进程,通过管道符把所有进程交给grep后,grep会筛选出于sshd相关的行作为结果输出
tee 管道(三通管道)
简介
tee 管道:三通管道,即把数据交给另一个程序继续处理,同时又保存一份副本到文件中。

形象理解:
想象一个 T 形水管三通头:
- 水流(数据)从一端进入
- 分成两路:一路继续向前流(交给下一个命令),一路分流到侧面(保存到文件)
案例
[root@localhost ~]# cat /etc/passwd | tee 88.txt | tail -1
jack:x:6674:6676::/home/jack:/bin/bash
查看 tee 保存的文件内容:
[root@localhost ~]# cat 88.txt
问题:88.txt 文件中是什么内容?一行还是所有行?
答案:所有行!因为 tee 保存的是命令 1(
cat)处理的全部结果,而tail -1只是从管道中取走的最后一行。
参数传递 xargs
为什么需要 xargs?
有些命令(如 cp、rm、mv)比较特殊,它们不接受管道的标准输入作为参数。
打个比方:
管道就像传送带,把上一个命令的输出传递给下一个命令。但 rm、cp 这些命令”脾气倔”,不吃传送带上的东西,只接受直接给它们的参数。
xargs 就是翻译官,把传送带上的内容”翻译”成这些命令能理解的参数格式。
案例演示
步骤 1:环境准备,创建一些文件
[root@localhost ~]# touch /home/file{1..5}
[root@localhost ~]# ls /home
file1 file2 file3 file4 file5
步骤 2:创建要删除的文件列表
[root@localhost ~]# vim files.txt
/home/file1
/home/file3
/home/file5
步骤 3:尝试直接用管道删除(失败)
[root@localhost ~]# cat files.txt | rm -rvf
# 查看/home下的文件,发现删除失败!rm 不会删除任何文件
为什么会失败? 因为
rm不接受管道的标准输入作为参数。它需要的是rm /home/file1 /home/file3 /home/file5这种参数形式。
步骤 4:加上 xargs 成功连接 rm 命令
[root@localhost ~]# cat files.txt | xargs rm -rvf
已删除"/home/file1"
已删除"/home/file3"
已删除"/home/file5"
[root@localhost ~]# ls /home
file2 file4
xargs 的作用原理:
# 没有 xargs:
cat files.txt | rm -rvf
# rm 收到的是标准输入,但它看不懂
# 有 xargs:
cat files.txt | xargs rm -rvf
# xargs 把文件内容转换成参数格式:rm -rvf /home/file1 /home/file3 /home/file5
xargs 常用用法
# 查找所有 .log 文件并删除
find /var/log -name "*.log" | xargs rm -f
# 查找并统计行数
find . -name "*.txt" | xargs wc -l
# 处理文件名中包含空格的情况(使用 -d 指定分隔符)
find . -name "*.txt" -print0 | xargs -0 rm -f
综合场景(了解)
场景一:日志分析
# 查看访问日志中状态码为 404 的请求,并统计数量
cat /var/log/nginx/access.log | grep " 404 " | wc -l
# 查看错误日志并保存到文件
cat /var/log/nginx/error.log | tee /tmp/nginx_errors.txt | grep "critical"
场景二:批量文件操作
# 查找所有超过 100MB 的日志文件并删除
find /var/log -name "*.log" -size +100M | xargs rm -f
# 查找所有 .conf 配置文件并备份
find /etc -name "*.conf" | xargs -I {} cp {} {}.bak
场景三:自动化脚本中的输出管理
# 安装软件包,只保留错误输出
yum install -y nginx &>/dev/null
# 安装软件包,将日志追加到文件
yum install -y nginx >> /var/log/install.log 2>&1
常见问题
Q1:> 和 >> 有什么区别?
| 操作符 | 行为 | 类比 |
|---|---|---|
> | 覆盖写入,清空文件后再写入 | 把黑板擦干净再写新内容 |
>> | 追加写入,在文件末尾添加 | 在黑板内容的最后一行继续写 |
Q2:2>&1 是什么意思?
2>&1 的含义是:把标准错误(FD 2)重定向到标准输出(FD 1)当前指向的位置。
# 正确输出和错误输出都写入到同一个文件
command > output.log 2>&1
# 或者使用 bash 快捷写法
command &> output.log
注意:顺序很重要!
command > output.log 2>&1和command 2>&1 > output.log的效果是不同的。
Q3:管道和重定向有什么区别?
| 特性 | 管道 | | 重定向 >、< |
|——|———|—————-|
| 连接对象 | 命令与命令 | 命令与文件 |
| 数据流向 | 命令1 的输出 → 命令2 的输入 | 命令的输出 → 文件,或 文件的输入 → 命令 |
| 使用场景 | 组合多个命令处理数据 | 保存输出结果或读取文件内容 |
Q4:如何只保存正确输出,忽略错误输出?
# 正确输出保存到文件,错误输出丢弃到黑洞
command > output.log 2>/dev/null
最佳实践
重定向前先确认文件是否存在
>会覆盖已有文件,谨慎使用- 不确定时使用
>>追加
生产环境中合理管理输出
- 不需要输出时用
&>/dev/null避免产生无用日志 - 需要追踪时用
>>追加到日志文件
- 不需要输出时用
管道命令链不要太长
- 一般建议不超过 3-4 个管道连接
- 太长可考虑写成 shell 脚本
使用 xargs 处理大量文件时注意安全
- 文件名含空格时使用
-print0和-0参数 - 删除前先用
ls或echo预览
- 文件名含空格时使用
善用 tee 同时查看和保存输出
command | tee output.log | less
总结
通过本文的学习,你应该掌握了:
- 理解文件描述符(FD)的概念和作用
- 使用
>和>>进行正确输出重定向 - 使用
2>和2>>进行错误输出重定向 - 使用
<进行输入重定向 - 使用
|管道连接多个命令 - 使用
tee同时查看和保存输出 - 使用
xargs将标准输入转换为命令行参数
学习建议:重定向和管道是 Linux 命令行最强大的特性之一。建议在自己的虚拟机上多练习这些命令,尝试将不同命令组合起来,你会发现 Linux 命令行的无限可能!