管道
bash
command1 | command2 [ | command3 ... ]
ls -l | grep ".txt" # 列出当前目录下的文件,然后过滤出包含".txt"的行
ps aux | grep "nginx" # 查看所有进程,然后过滤出包含"nginx"的进程
- 管道符|左边命令的输出会作为管道符右边命令的输入。
- 可以串联多个管道,形成管道链。
在Linux中,管道(pipe)是一种进程间通信(IPC)的机制。本质上是内核在内存中维护的固定大小的缓冲区。 管道是半双工通信,先进先出。管道有两种类型:匿名管道(anonymous pipes)和命名管道(named pipes),在 shell 脚本和命令行操作中广泛应用。
匿名管道 |
匿名管道只能用于具有亲缘关系的进程(如父子进程)之间。
匿名管道不是文件系统中的一个持久化对象(没有文件名)。它是在内存中创建的一个缓冲区,通过 pipe() 系统调用返回两个文件描述符:一个用于读取(fd[0]),一个用于写入(fd[1])。这两个文件描述符只存在于父进程的文件描述符表中。当父进程调用 fork() 创建子进程时,子进程会继承父进程的所有文件描述符的副本。这样,父子进程就拥有了指向同一个管道的文件描述符。
bash
# 管道与重定向结合
command1 | command2 > output.txt
command1 < input.txt | command2 > output.txt
# 错误输出重定向
command1 2>&1 | command2
命名管道
如果需要在不相关的进程间进行管道通信,应该使用 命名管道(Named Pipe 或 FIFO)。命名管道在文件系统中有一个路径名(如 /tmp/myfifo)。任何知道该路径名的进程,都可以像操作普通文件一样,通过 open()、read()、write() 来访问它,从而实现了非亲缘进程间的通信。
bash
echo "test data" | tee >(grep "test") >(wc -l)
┌─────────────────────────────────────────────────────────────┐
│ 命令执行环境 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ echo进程 │ 产生数据: "test data\n"
└─────────────────┘
│
▼ 通过匿名管道传递
┌─────────────────┐
│ tee进程 │ 读取标准输入,复制到多个输出
└─────────────────┘
│
├──────────────────┬───────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────────┐ ┌─────────────┐
│ 标准输出 │ │ 进程替换输出1 │ │ 进程替换输出2 │
│ (终端) │ │ /dev/fd/63 │ │ /dev/fd/64 │
└─────────────┘ └─────────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
显示: "test data" ┌─────────────┐ ┌─────────────┐
│ grep进程 │ │ wc进程 │
│ 过滤"test" │ │ 统计行数 │
└─────────────┘ └─────────────┘
│ │
▼ ▼
输出: "test data" 输出: "1"
│ │
└─────┬─────────────┘
▼
┌─────────────┐
│ 终端 │ ← 最终显示所有输出
│ 可能显示: │
│ test data │
│ 1 │
│ test data │
└─────────────┘