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

处理流程:

  1. docker images:获取所有镜像列表
  2. cut -d' ' -f1:提取第一列(镜像名)
  3. tail -n +2:跳过标题行
  4. sort -u:去重排序
  5. wc -l:统计行数(即镜像数量)

许多命令(如 git 的 plumbing 命令)专为管道链设计

5.4 命名管道

跨进程通信的高级用法

# 创建命名管道
mkfifo my_pipe

# 终端A:写入管道
ls -l > my_pipe

# 终端B:读取管道
cat < my_pipe

命名管道以文件形式持久化,适合构建系统级通信通道。

6. 总结

重定向和管道是 Linux 命令行的核心能力:

  • 文件重定向>/>> 控制输出,< 控制输入
  • 描述符操作2>&1 合并错误流,&> 同时重定向
  • 管道链| 构建高效处理流水线
  • 命名管道:实现持久化进程通信

掌握这些技巧,能用简单命令组合解决复杂问题——这正是 Unix 哲学的精髓所在。


原始标题:Pipes and Redirection in Linux | Baeldung on Linux