给一个pipe的用法示例

以下是一些 Linux 管道(|)的用法示例,展示如何将多个命令组合使用:


示例 1:查找特定进程

1
ps aux | grep nginx
  • 作用:列出所有进程,筛选出包含 nginx 的进程。
  • ps aux:显示所有进程的详细信息。
  • |:将 ps aux 的输出传递给 grep
  • grep nginx:仅保留包含 nginx 的行。

示例 2:统计文件数量

1
ls -l /var/log | wc -l
  • 作用:统计 /var/log 目录下的文件/文件夹数量。
  • ls -l:以长格式列出文件。
  • wc -l:统计输入的行数(即文件数量)。

示例 3:实时监控日志中的错误

1
tail -f /var/log/syslog | grep "ERROR"
  • 作用:实时跟踪日志文件,仅显示包含 ERROR 的行。
  • tail -f:持续输出文件的新增内容。
  • grep "ERROR":过滤出包含 ERROR 的行。

示例 4:分析磁盘空间占用

1
du -sh /* | sort -rh | head -n 5
  • 作用:列出根目录下占用空间最大的前 5 个目录。
  • du -sh /*:统计根目录下所有子目录的大小(人类可读格式)。
  • sort -rh:按人类可读的数字逆序排序(如 10G > 1G)。
  • head -n 5:仅显示前 5 行结果。

示例 5:提取特定数据并计算

1
cat access.log | awk '{print $1}' | sort | uniq -c | sort -nr
  • 作用:统计日志文件中访问量前几的 IP 地址。
  • cat access.log:读取日志文件。
  • awk '{print $1}':提取第一列(假设为 IP 地址)。
  • sort:排序 IP。
  • uniq -c:统计每个 IP 出现的次数。
  • sort -nr:按次数降序排序。

示例 6:组合多个命令处理文本

1
echo "Hello World! This is a test." | tr 'a-z' 'A-Z' | sed 's/ /_/g'
  • 输出HELLO_WORLD!_THIS_IS_A_TEST.
  • echo:生成文本。
  • tr 'a-z' 'A-Z':将所有字母转为大写。
  • sed 's/ /_/g':将空格替换为下划线。

示例 7:处理命令输出中的错误

1
ls /non_existent_dir 2>&1 | grep "No such file"
  • 作用:捕获 ls 的错误输出并筛选特定信息。
  • 2>&1:将标准错误(stderr)重定向到标准输出(stdout)。
  • grep:过滤出包含 No such file 的行。

管道的核心思想

通过 | 将前一个命令的标准输出传递给后一个命令的标准输入,实现多命令协作。常用于日志分析、文本处理、系统监控等场景。

写个pipe函数的用法示例

在 Linux 系统编程中,pipe 函数用于创建进程间通信(IPC)的管道。以下是一个使用 pipe 函数的 C 语言示例,展示父子进程通过管道通信的过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

int main() {
int pipe_fd[2]; // pipe_fd[0] 读端, pipe_fd[1] 写端
char buffer[100];
pid_t pid;

// 1. 创建管道
if (pipe(pipe_fd) == -1) {
perror("pipe() failed");
return 1;
}

// 2. 创建子进程
pid = fork();
if (pid == -1) {
perror("fork() failed");
return 1;
}

if (pid == 0) { // 子进程:读取数据
close(pipe_fd[1]); // 关闭写端(子进程不需要)

read(pipe_fd[0], buffer, sizeof(buffer));
printf("Child received: %s\n", buffer);

close(pipe_fd[0]); // 关闭读端
return 0;

} else { // 父进程:写入数据
close(pipe_fd[0]); // 关闭读端(父进程不需要)

const char *msg = "Hello from parent!";
write(pipe_fd[1], msg, strlen(msg) + 1); // +1 包含字符串结尾的 '\0'
printf("Parent sent: %s\n", msg);

close(pipe_fd[1]); // 关闭写端
wait(NULL); // 等待子进程结束
}

return 0;
}

代码解析:

  1. 创建管道

    1
    2
    int pipe_fd[2];
    pipe(pipe_fd); // 成功返回 0,失败返回 -1
    • 创建两个文件描述符:pipe_fd[0](读端)和 pipe_fd[1](写端)。
  2. 父子进程通信

    • 父进程关闭读端,向写端写入数据。
    • 子进程关闭写端,从读端读取数据。
  3. 关键操作

    • write(pipe_fd[1], data, size):向管道写入数据。
    • read(pipe_fd[0], buffer, size):从管道读取数据。
    • 必须关闭未使用的文件描述符,否则可能导致阻塞。

输出结果:

1
2
Parent sent: Hello from parent!
Child received: Hello from parent!

管道(pipe)的核心特性:

  1. 半双工通信:数据只能单向流动(父→子 或 子→父)。
  2. 内核缓冲区:数据暂存在内核的缓冲区中(默认大小通常为 64KB)。
  3. 进程关系:通常用于有亲缘关系的进程(如父子进程)。
  4. 文件描述符管理:需要显式关闭未使用的描述符,避免资源泄漏。

常见应用场景:

  • 实现 Shell 的管道符(如 cmd1 | cmd2)。
  • 进程间传递结构化数据。
  • 控制进程执行流程(如父进程向子进程发送命令)。