1. 引言
大多数 shell 都能改变应用程序的输入输出流向,将输出从终端转向文件或其他应用,或从文件读取输入替代终端。本文将深入探讨 Linux 中的管道(pipe)和重定向(redirection)机制。
2. 标准输入与输出
理解 shell 重定向前,需先掌握标准输入输出流程:
- 所有应用都有三个文件描述符:标准输入(stdin)、标准输出(stdout)和标准错误(stderr)
- 标准输入:交互式程序的默认输入源,终端运行时通常关联键盘
- 标准输出:程序默认输出目标,通常关联终端,但可能因性能缓冲(尤其网络环境)
文件描述符 ID:stdin=0,stdout=1,stderr=2(POSIX 标准定义)
3. 重定向输出到文件
3.1 基础重定向
将程序输出写入文件而非终端,使用 >
操作符:
ls > files
执行后:
$ cat files
file1
file2
...
3.2 追加模式
使用 >>
追加内容(避免覆盖原文件):
echo "First line" > log.txt
echo "Second line" >> log.txt
3.3 重定向标准错误
单独重定向错误输出需指定文件描述符 ID(stderr=2):
cat missing_file.txt 2> errors.log
同时重定向 stdout 和 stderr(bash/zsh 支持):
command &> all_output.log
3.4 文件描述符操作
合并 stderr 到 stdout(常用技巧):
command 2>&1
交换 stdout 和 stderr(需临时文件描述符):
command 3>&2 2>&1 1>&3
⚠️ 踩坑:此语法在 bash 和 zsh 中行为不同,zsh 可能导致两者都输出到 stdout
3.5 多重定向
同时重定向不同描述符:
command > output.log 2> errors.log
合并到同一文件:
command > all.log 2>&1
4. 从文件读取输入
将文件内容作为程序输入使用 <
操作符:
sort < names.txt
等同于用户手动输入文件全部内容,但文件结束符(EOF)会自动触发程序处理完成。
5. 应用间管道
5.1 基础管道
用 |
连接应用(前一个 stdout 作为后一个 stdin):
ls -l | grep ".txt"
默认 stderr 不进入管道,仍会输出到终端
5.2 处理标准错误
将 stderr 纳入管道:
command 2>&1 | less
仅管道 stderr(需交换描述符):
command 3>&1 1>&2 2>&3 | grep "error"
5.3 管道链组合
构建复杂处理链(以 Docker 镜像统计为例):
docker images | cut -d' ' -f1 | tail -n +2 | sort -u | wc -l
处理流程:
docker images
:获取所有镜像列表cut -d' ' -f1
:提取第一列(镜像名)tail -n +2
:跳过标题行sort -u
:去重排序wc -l
:统计行数(即镜像数量)
许多命令(如 git 的 plumbing 命令)专为管道链设计
5.4 命名管道
跨进程通信的高级用法:
# 创建命名管道
mkfifo my_pipe
# 终端A:写入管道
ls -l > my_pipe
# 终端B:读取管道
cat < my_pipe
命名管道以文件形式持久化,适合构建系统级通信通道。
6. 总结
重定向和管道是 Linux 命令行的核心能力:
- 文件重定向:
>
/>>
控制输出,<
控制输入 - 描述符操作:
2>&1
合并错误流,&>
同时重定向 - 管道链:
|
构建高效处理流水线 - 命名管道:实现持久化进程通信
掌握这些技巧,能用简单命令组合解决复杂问题——这正是 Unix 哲学的精髓所在。