管道到 C 中的 grep 程序

Pipe to a grep program in C

我正在尝试将此 bash 命令:ps aux | grep bash 复制到 C 语言。我写了一些东西,但它似乎不起作用。结果字面意思是没有任何反应,在bash中再次打印提示。这是代码:

int main()
{

int pid;
int pip[2];
char *argexec1[] = {"/bin/grep", "bash", NULL};
char *argexec2[] = {"/bin/ps", "aux", NULL};

if (pipe(pip) == -1){
        perror("pipe error \n");
        exit(1);
}

if (pid = fork() == -1){
        perror("fork error");
        exit(1);
}

if (pid == 0)
{
        dup2(pip[0], 0);
        close(pip[1]);
        close(pip[0]);

        execvp("grep", argexec1);
        perror("exec1 failed\n");
        exit(1);

}

else
{
    dup2(pip[1], 1);
    close(pip[0]);
    close(pip[1]);

    execvp("ps", argexec2);
    perror("exec2 failed\n");
    exit(1);
}

在子进程中,如果execvp()失败,不调用exit()而是调用_ exit() 否则继承的 I/O 上下文可能会触发重复的 I/O 刷新和其他一些不希望发生的事情。

。 “==”比“=”多了一个higher precedence。这会使您的声明在这里失败:

if (pid = fork() == -1)

添加括号:

if ((pid = fork()) == -1)

这是您的程序,其中包含修正:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>


int main(void)
{
  int pid;
  int pip[2];
  char *argexec1[] = {"/bin/grep", "bash", NULL};
  char *argexec2[] = {"/bin/ps", "aux", NULL};

  if (pipe(pip) == -1){
    perror("pipe error \n");
    exit(1);
  }

  if ((pid = fork()) == -1){
    perror("fork error");
    exit(1);
  }

  if (pid == 0) {

    // Child process

    dup2(pip[0], 0);
    close(pip[1]);
    close(pip[0]);

    execvp("grep", argexec1);
    perror("exec1 failed\n");
    _exit(1);

  } else {

    // Father process

    dup2(pip[1], 1);
    close(pip[0]);
    close(pip[1]);

    execvp("ps", argexec2);
    perror("exec2 failed\n");
    exit(1);
  }

  return 0;
}

但实际上,如果你想让它像shell那样,你应该在退出程序之前等待命令结束和return最后一个进程的退出代码在管道中。所以,父亲应该启动两个进程并等待它们结束:

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

int main(void)
{
  int status1, status2;
  int pid1, pid2;
  int pip[2];
  char *argexec1[] = {"/bin/grep", "bash", NULL};
  char *argexec2[] = {"/bin/ps", "aux", NULL};

  if (pipe(pip) == -1){
    perror("pipe error \n");
    exit(1);
  }

  if ((pid1 = fork()) == -1){
    perror("fork error");
    exit(1);
  }

  if (pid1 == 0) {

    // Child process#1

    dup2(pip[0], 0);
    close(pip[1]);
    close(pip[0]);

    execvp("grep", argexec1);
    perror("exec1 failed\n");
    _exit(2);

  } else {

    // Father process

    if ((pid2 = fork()) == -1){
      perror("fork error");
      exit(1);
    }

    if (pid2 == 0) {

      // Child process#2

      dup2(pip[1], 1);
      close(pip[1]);
      close(pip[0]);

      execvp("ps", argexec2);
      perror("exec2 failed\n");
      _exit(2);
    
    } else {

      // Father process

      close(pip[0]);
      close(pip[1]);

      // Wait for the end of the programs
      if (-1 == waitpid(pid1, &status1, 0)) {
        perror("wait1 error");
        exit(1);
      }
      if (-1 == waitpid(pid2, &status2, 0)) {
        perror("wait2 error");
        exit(1);
      }

      // Return the exit code of the last program in the pipe
      if (WIFEXITED(status1)) {
        return WEXITSTATUS(status1);
      } else {
        // The process may have received a signal, return the whole status...
        return status1;
      }

    }

  }

  return 0;
}