【问题标题】:Executing cat|grep|grep using 2 pipes使用 2 个管道执行 cat|grep|grep
【发布时间】:2020-07-22 03:39:23
【问题描述】:

标题不言自明,这是我当前的代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main() {

  pid_t pid ;
  int fd[2], fd2[2];
  pipe(fd);
  pipe(fd2);
  pid = fork(); 

  if(pid == 0) {
    close(1);
    dup(fd[1]);
    close(fd[0]);
    close(fd[1]);

    char *exp[] = {"cat", "filename.txt", NULL};
    execvp("cat", exp);
    exit(EXIT_FAILURE);
  } 
  else if(pid > 0) {
    close(1);
    dup(fd2[1]);
    close(fd2[0]);
    close(fd2[1]);

    char *exp[] = {"grep", "-w", "stringname", NULL};
    execvp(exp[0], exp);

    pid_t pid2=fork();

    close(0);
    dup(fd[0]);
    close (fd[1]);
    close(fd[0]);

  char *exp2[] = {"grep", "-c", "stringname", NULL};
  execvp(exp2[0], exp2);

  exit(EXIT_FAILURE);
  }

  else {
    printf("Error in forking");
    exit(EXIT_FAILURE);
  }
  close(fd[0]);
  close(fd[1]);
  close(fd2[0]);
  close(fd2[1]);
  return 0;
}

目前程序正在编译但未执行(它在执行时卡在某个地方,我没有得到任何输出),任何关于我做错了什么的帮助以及如何解决它?

【问题讨论】:

  • 您没有关闭足够的文件描述符。每个进程需要关闭所有四个管道文件描述符。
  • 刚刚这样做了,结果还是一样,我想我应该在创建第二个进程后添加一个if(pid2&gt;0),现在就这样做
  • 这样做了,结果也没有任何变化。
  • 正在写入 fd2grep 在读取时被阻止。
  • @WilliamPursell 所以你的意思是我在父进程开始时删除了close(fd2[0])

标签: c grep pipe cat


【解决方案1】:

你的代码有一些问题:

  1. 第一个 grep 之后的 execvp(exp[0], exp); 将在第二个 fork() 之前执行。这是一个逻辑错误。
  2. 我不太明白您如何使用管道的文件描述符。您应该将标准输入和标准输出替换为适当的管道末端并关闭所有其他末端。

我用这些更改重写了您的代码,使用dup2 使其更简洁:

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
    int pipes[4];

    // Create two pipes
    pipe(pipes);
    pipe(pipes + 2);

    // Execute cat
    if (fork() == 0) {
        // Replace output with write end of first pipe
        dup2(pipes[1], 1);

        // Close all ends of pipes (we already copied it with `dup2`)
        close(pipes[0]);
        close(pipes[1]);
        close(pipes[2]);
        close(pipes[3]);

        char *exp[] = {"cat", "filename.txt", NULL};
        execvp(exp[0], exp);
        perror("cat failed");
        exit(EXIT_FAILURE);
    } else {
        // Execute first grep
        if (fork() == 0) {
            // Replace input with read end of 1st pipe
            dup2(pipes[0], 0);

            // Replace output with write end of 2nd pipe
            dup2(pipes[3], 1);

            // Close all ends of pipes
            close(pipes[0]);
            close(pipes[1]);
            close(pipes[2]);
            close(pipes[3]);

            char *exp[] = {"grep", "-w", "stringname", NULL};
            execvp(exp[0], exp);
            perror("first grep failed");
            exit(EXIT_FAILURE);
        } else {
            // Execute second grep
            if (fork() == 0) {
                // Replace input with read end of 2nd pipe
                dup2(pipes[2], 0);

                // Close all ends of pipes
                close(pipes[0]);
                close(pipes[1]);
                close(pipes[2]);
                close(pipes[3]);

                char *exp[] = {"grep", "-c", "stringname", NULL};
                execvp(exp[0], exp);
                perror("second grep failed");
                exit(EXIT_FAILURE);
            }
        }
    }

    // Close all ends of pipes
    close(pipes[0]);
    close(pipes[1]);
    close(pipes[2]);
    close(pipes[3]);

    for (int i = 0; i < 3; i++) {
        wait(NULL);
    }

    return 0;
}

【讨论】:

  • 代码末尾的 for 循环的目的是什么
  • wait() 是必需的,因为只有父进程才能到达这一点。我们需要等待使用fork() 创建的所有子进程,以确保它们已完成并释放资源。
猜你喜欢
  • 2017-05-20
  • 1970-01-01
  • 2017-01-12
  • 1970-01-01
  • 1970-01-01
  • 2021-09-10
  • 2019-02-18
  • 2019-12-31
  • 2010-10-12
相关资源
最近更新 更多