Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
512 views
in Technique[技术] by (71.8m points)

c - Combining two commands with a pipe

I'm trying to "merge" two commands in one (nonexistent) command and pipe it.By this I mean.. Suppose that you have these two commands: grep text < file.txt | wc -l > out.txt, the (nonexistent) command that could represent this two commands could be something like (grepwc -l < file.txt) which then outputs the number of lines into the out.txt. Basically these (grepwc) command should have the same behavior as the grep text < file.txt | wc -l > out.txt but shorter.

I tried something like this, but I think my approach is far to accomplish the goal. I use a structure named commlist which contains the commands already parsed by cmd, argc and argv. inputfile and outputfile are the pathnames of the files used on open().

The struct I'm using.

typedef struct command {
char *cmd;              
int argc;               
char *argv[MAXARGS+1];  
struct command *next;
} COMMAND;

and the code:

void execute(COMMAND *commlist) {
  int fd[2];
  pid_t pid;
  int n_pipes=2; //pipes needed
  COMMAND *aux = commlist;

  int i;
  for(i=0;i<n_pipes; i++){
    int oldfd = 0;

    if(fd[0]!=0){
      close(fd[1]);
      oldfd = fd[0];
    }
      pipe(fd);

      if((pid=fork())<0){perror("Fork Failed");}
      else 
        if(pid == 0){

          if(inputfile!=NULL){
            int in = open(inputfile,O_RDONLY);
            dup2(in,STDIN_FILENO);
            inputfile = NULL;
          }

          if(outputfile != NULL){
            int out = open(outputfile, O_RDWR |O_CREAT | O_TRUNC, S_IRWXU);
            dup2(out,STDOUT_FILENO);
            outputfile = NULL;
          }

          if(oldfd)
            dup2(oldfd,STDIN_FILENO);

          if(commlist->cmd == "grepwc"){
            if(i==0){
              if(execlp("grep","grep","celio",NULL)<0){
                perror("Bad command");
                exit(1);    
              }
            }

            if(i==1){
              if(execlp("wc","wc","-l",NULL) < 0){
                perror("Bad command");
                exit(1);
              }
            }
          }
        }//child
  }
}

The full code is here:

http://pastebin.com/tYGWwUjS

http://pastebin.com/sNJhEg2Y

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your approach is indeed a bit overcomplicated. This can be achieved with just one childprocess and a single pipe (just as in the original shell command). Let's have a look at it:

grep text < file.txt | wc -l > out.txt

This

  • creates a pipe
  • forks two processes
  • makes grep write to the pipe
  • makes wc read from the pipe

But it is enough to fork only one process, since we do not need to return to the parent process. This results in the following code:

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

int main (void) {
    int fd[2];

    pipe(fd);

    if (fork()) {
        // Child process
        dup2(fd[0], 0); // wc reads from the pipe
        close(fd[0]);
        close(fd[1]);
        execlp("wc", "wc", "-l", NULL);
    } else {
        // Parent process
        dup2(fd[1], 1); // grep writes to the pipe
        close(fd[0]);
        close(fd[1]);
        execlp("grep", "grep", "celio", NULL);
    }
    exit(EXIT_FAILURE);
}

The exit() is only reached if one of the execlp()'s fails.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...