简体   繁体   中英

Pipe to a grep program in C

I'm trying to replicate this bash command: ps aux | grep bash ps aux | grep bash to C language. I have written something but it doesn't seem to work. The result is literally that nothing happens, the prompt is printed again in bash. This is the code:

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);
}

In the child process, if execvp() fails, don't call exit() but _ exit() otherwise the inherited I/O contexts may trigger duplicate I/O flushes and several other undesirable things.

. "==" has a higher precedence than "=". This makes your statement fail here:

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

Add parenthesis:

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

Here is your program with the fixes:

#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;
}

But actually, if you want to make it like the shell, you are supposed to wait for the end of the commands before exiting the program and return the exit code of the last process in the pipe. So, the father should launch two processes and wait for their end:

#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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM