linux里面的过滤符号 | 是如何实现的

devtools/2025/2/28 8:44:17/

ls -l | grep ".txt" 的实现过程涉及无名管道的创建、进程的创建(fork())以及输入输出的重定向(dup2())。以下是详细的实现步骤和代码示例:


实现步骤

  1. 创建无名管道

    • 使用pipe()系统调用创建一个无名管道,管道会返回两个文件描述符:pipefd[0](读端)和pipefd[1](写端)。

  2. 创建子进程

    • 使用fork()创建子进程。父进程和子进程会共享管道的文件描述符。

  3. 重定向输入输出

    • 在父进程中:

      • 关闭管道的读端(pipefd[0])。

      • 将标准输出(STDOUT_FILENO)重定向到管道的写端(pipefd[1])。

      • 执行ls -l命令,其输出会写入管道。

    • 在子进程中:

      • 关闭管道的写端(pipefd[1])。

      • 将标准输入(STDIN_FILENO)重定向到管道的读端(pipefd[0])。

      • 执行grep ".txt"命令,其输入会从管道读取。

  4. 等待子进程完成

    • 父进程使用wait()等待子进程结束。


代码实现

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>int main() {int pipefd[2]; // 用于存储管道的文件描述符pid_t pid;// 创建无名管道if (pipe(pipefd) == -1) {perror("pipe");exit(EXIT_FAILURE);}// 创建子进程pid = fork();if (pid == -1) {perror("fork");exit(EXIT_FAILURE);}if (pid == 0) { // 子进程:执行 grep ".txt"// 关闭管道的写端close(pipefd[1]);// 将标准输入重定向到管道的读端if (dup2(pipefd[0], STDIN_FILENO) == -1) {perror("dup2");exit(EXIT_FAILURE);}// 关闭管道的读端(已经重定向,不再需要)close(pipefd[0]);// 执行 grep ".txt"execlp("grep", "grep", ".txt", NULL);perror("execlp"); // 如果 execlp 失败exit(EXIT_FAILURE);} else { // 父进程:执行 ls -l// 关闭管道的读端close(pipefd[0]);// 将标准输出重定向到管道的写端if (dup2(pipefd[1], STDOUT_FILENO) == -1) {perror("dup2");exit(EXIT_FAILURE);}// 关闭管道的写端(已经重定向,不再需要)close(pipefd[1]);// 执行 ls -lexeclp("ls", "ls", "-l", NULL);perror("execlp"); // 如果 execlp 失败exit(EXIT_FAILURE);}// 父进程等待子进程结束wait(NULL);return 0;
}
 

代码说明

  1. pipe(pipefd)

    • 创建一个无名管道,pipefd[0]是读端,pipefd[1]是写端。

  2. fork()

    • 创建子进程。父进程和子进程会同时运行,但通过if (pid == 0)区分逻辑。

  3. dup2(pipefd[1], STDOUT_FILENO)

    • 将标准输出重定向到管道的写端,使得ls -l的输出写入管道。

  4. dup2(pipefd[0], STDIN_FILENO)

    • 将标准输入重定向到管道的读端,使得grep ".txt"从管道读取输入。

  5. execlp()

    • 替换当前进程的映像,执行指定的命令(如ls -lgrep ".txt")。

  6. wait(NULL)

    • 父进程等待子进程结束,避免僵尸进程。


运行结果

运行该程序后,会输出当前目录下所有包含.txt的文件列表,效果与直接在终端运行ls -l | grep ".txt"相同。


总结

通过无名管道和进程间通信,我们可以实现类似Shell管道的功能。无名管道的核心在于:

  • 父子进程共享文件描述符。

  • 通过dup2()重定向输入输出。

  • 使用execlp()执行命令。


http://www.ppmy.cn/devtools/163309.html

相关文章

说说 Spring MVC 的执行流程

Spring MVC 是一个基于 Java 的轻量级、开源的 Web 框架&#xff0c;用于构建 Web 应用程序。它通过将请求处理的各个阶段解耦&#xff0c;使得开发更加灵活和模块化。以下是 Spring MVC 的执行流程&#xff0c;从用户发起请求到返回响应的整个过程&#xff1a; --- ### 1. 用…

图片爬取案例

修改前的代码 但是总显示“失败” 原因是 修改之后的代码 import requests import os from urllib.parse import unquote# 原始URL url https://cn.bing.com/images/search?viewdetailV2&ccidTnImuvQ0&id5AE65CE4BE05EE7A79A73EEFA37578E87AE19421&thidOIP.TnI…

毛泽东思想“活的灵魂”

关于毛泽东思想“活的灵魂”的构成及其内涵&#xff0c;综合历史文献与权威表述&#xff0c;核心内容整理如下&#xff1a; 一、毛泽东思想活的灵魂的权威定义 根据十一届六中全会《关于建国以来党的若干历史问题的决议》&#xff08;1981年&#xff09;&#xff0c;毛泽东思想…

机器学习数学基础:33.肯德尔和谐系数教程

肯德尔和谐系数教程 一、定义与用途 肯德尔和谐系数&#xff08;Kendall’s W&#xff09;是一种用于衡量多个评价者对一组对象进行评价时&#xff0c;评价结果一致性程度的统计量。它的取值范围在0到1之间。当W \ 0时&#xff0c;表示评价者之间的评价完全不一致&#xff1…

Spring Boot启动过程?

目录 1. 启动入口 2. SpringApplication 初始化 3. 准备环境 4. 创建应用上下文(ApplicationContext) 5. 准备应用上下文 6. 刷新应用上下文 7. 启动 Web 服务器(若为 Web 应用) 8. 发布 ApplicationStartedEvent 事件 9. 执行 Runner 10. 发布 ApplicationReady…

macos下cocoapods的学习

step1&#xff1a;升级ruby $ /bin/bash -c " $ (curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" $ brew update $ brew install ruby $ echo export PATH"/usr/local/opt/ruby/bin:$PATH" >> ~/.bash_profile …

STM32编译过程

STM32编译过程 1. 编译过程介绍2. 程序的组成、存储与运行3. 编译工具链3.1 armcc 工具3.2 armasm 工具3.3 armlink 工具3.4 armar 工具3.5 fromelf 工具 4. MDK工程的文件类型 1. 编译过程介绍 编译MDK 软件使用的编译器是 armcc 和 armasm&#xff0c;它们根据每个 c/c 和汇编…

MAC 安装Tensorflow简单方法

MacOS M1 pro安装tensorflow 1、环境配置&#xff08;必需&#xff09; PYTHON版本&#xff1a;3.11.0&#xff0c;python采用homebrew安装。&#xff08;已有python或更高版本可跳过&#xff0c;更高版本未经过测试&#xff0c;题主自认为可行&#xff09; brew install pyt…