将n个命令与shell中的pipe道连接起来?

我试图在C中实现一个shell。我可以用一个简单的execvp()来执行简单的命令,但是其中一个要求是pipe理这样的命令:“ls -l | head | tail -4” '循环,只有一个'pipe()'语句redirect标准input和标准输出。 现在我有点失落了。

N =简单命令的数目(例子中的3个:ls,head,tail)命令=命令的结构列表,如下所示:

commands[0].argv[0]: ls commands[0].argv[1]: -l commands[1].argv[0]: head commands[2].argv[0]: tail commands[2].argv[1]: -4 

所以,我做了for循环,并开始redirect标准input和标准输出,以连接所有的命令与pipe道,但…我只是无知,为什么它不工作。

 for (i=0; i < n; i++){ pipe(pipe); if(fork()==0){ // CHILD close(pipe[0]); close(1); dup(pipe[1]); close(pipe[1]); execvp(commands[i].argv[0], &commands[i].argv[0]); perror("ERROR: "); exit(-1); }else{ // FATHER close(pipe[1]); close(0); dup(pipe[0]); close(pipe[0]); } } 

我想创build的是一个childed进程的“线”:

[ls -l] —- pipe —-> [head] —- pipe —-> [tail -4]

所有这些进程都有一个根(运行我的shell的过程),所以,第一个父亲也是shell进程的孩子,我已经有点疲惫了,请问有谁能帮我一下吗?

我甚至不确定孩子是否应该是执行命令的人。

多谢你们 !!

这里没有什么复杂的,只要记住最后一个命令应该输出到原始进程的文件描述符1,第一个应该从原始进程文件描述符0中读取。你只是按顺序产生进程,沿着input端previois pipe调用。

所以,这里是types:

 #include <unistd.h> struct command { const char **argv; }; 

用一个简单明确的语义做一个帮助函数:

 int spawn_proc (int in, int out, struct command *cmd) { pid_t pid; if ((pid = fork ()) == 0) { if (in != 0) { dup2 (in, 0); close (in); } if (out != 1) { dup2 (out, 1); close (out); } return execvp (cmd->argv [0], (char * const *)cmd->argv); } return pid; } 

这里是主要的叉子程序:

 int fork_pipes (int n, struct command *cmd) { int i; pid_t pid; int in, fd [2]; /* The first process should get its input from the original file descriptor 0. */ in = 0; /* Note the loop bound, we spawn here all, but the last stage of the pipeline. */ for (i = 0; i < n - 1; ++i) { pipe (fd); /* f [1] is the write end of the pipe, we carry `in` from the prev iteration. */ spawn_proc (in, fd [1], cmd + i); /* No need for the write end of the pipe, the child will write here. */ close (fd [1]); /* Keep the read end of the pipe, the next child will read from there. */ in = fd [0]; } /* Last stage of the pipeline - set stdin be the read end of the previous pipe and output to the original file descriptor 1. */ if (in != 0) dup2 (in, 0); /* Execute the last stage with the current process. */ return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv); } 

而一个小testing:

 int main () { const char *ls[] = { "ls", "-l", 0 }; const char *awk[] = { "awk", "{print $1}", 0 }; const char *sort[] = { "sort", 0 }; const char *uniq[] = { "uniq", 0 }; struct command cmd [] = { {ls}, {awk}, {sort}, {uniq} }; return fork_pipes (4, cmd); } 

似乎工作。 🙂

首先,你过早地closures了pipe道。 只closures当前进程中不需要的结尾,并记住closuressubprocess中的stdin / stdout。

其次,你需要记住上一个命令的fd。 所以,对于两个进程,这看起来像:

 int pipe[2]; pipe(pipe); if ( fork() == 0 ) { /* Redirect output of process into pipe */ close(stdout); close(pipe[0]); dup2( pipe[1], stdout ); execvp(commands[0].argv[0], &commands[0].argv[0]); } if ( fork() == 0 ) { /* Redirect input of process out of pipe */ close(stdin); close(pipe[1]); dup2( pipe[0], stdin ); execvp(commands[1].argv[0], &commands[1].argv[0]); } /* Main process */ close( pipe[0] ); close( pipe[1] ); waitpid(); 

现在您的工作是添加error handling,并为n个进程生成n-1个pipe道来启动。 第一个fork()块中的代码需要针对进程1..n-1的适当pipe道运行,并且针对进程2..n的第二个fork()块中的代码运行。