使用系统调用fork()的多个管道实现execvp()wait()pipe() – 它根本不起作用

我需要实现处理多个管道命令的shell。 例如,我需要能够处理这个: ls | grep -i cs340 | sort | uniq | cut -c 5 ls | grep -i cs340 | sort | uniq | cut -c 5 ls | grep -i cs340 | sort | uniq | cut -c 5 。 我假设问题是我没有将前一个命令的输出传递给下一个命令的输入。 当我执行我的代码时,它没有给我输出。 我正在使用这个伪代码:

 for cmd in cmds if there is a next cmd pipe(new_fds) fork if child if there is a previous cmd dup2(old_fds[0], 0) close(old_fds[0]) close(old_fds[1]) if there is a next cmd close(new_fds[0]) dup2(new_fds[1], 1) close(new_fds[1]) exec cmd || die else if there is a previous cmd close(old_fds[0]) close(old_fds[1]) if there is a next cmd old_fds = new_fds if there are multiple cmds close(old_fds[0]) close(old_fds[1]) 

以下是处理多个管道的函数的源代码。

 void execute_multiple_commands(struct command ** commands_to_exec, int num_commands_p) { pid_t status; int i, err; int new_fd[2], old_fd[2]; pid_t pid, cpid; // creating child process if ( (cpid = fork()) == -1) { fprintf(stderr, "Could not create child process, exiting..."); exit(1); } if (cpid == 0) // in the child process we run multiple pipe handling { for (i = 0; i < num_commands_p; i++) // for each cmd in cmds { if (i+1 < num_commands_p) // if there is next cmd pipe(new_fd); if ( (pid = fork()) == -1) { fprintf(stderr, "Could not create child process, exiting..."); exit(1); } if (pid == 0) // if child { if (i != 0) // if there is a previous command { dup2(old_fd[0], 0); // setting up old_pipe to input into the child close(old_fd[0]); close(old_fd[1]); } if (i+1 args[0], commands_to_exec[i]->args); status = err; exit(err); } } else { waitpid(pid, &status, 0); if (status == -1) exit(1); if (i != 0) // if there a previous command { close(old_fd[0]); close(old_fd[1]); } if (i+1 < num_commands_p) // if there a next cmd { old_fd[0] = new_fd[0]; old_fd[1] = new_fd[1]; } exit(0); } // end if } // end for if (i) // if there a multiple commands { close(old_fd[0]); close(old_fd[1]); } } else // in the parent process we are waiting for child to handle multiple pipes waitpid(cpid, &status, 0); } 

函数execvp()接受结构数组。 我检查了所有解析部分,它工作正常。 这是我遇到麻烦的execute_multiple_commands()函数。

这是struct的代码:

 // name: command // desc: holds one command (meaning that it can be // more than one token in that command) // "ls -la" will be an example of one command // holds num of tokens in command array struct command { char ** args; int num_args; }; 

我建议一个新的策略,R2:

 function do(commands) if commands is of size 1 exec commands[0] || die split commands into c1 (first command) c2 (the rest of them) open if fork close input end of pipe dup output of pipe to stdin do (c2) || die close output end of pipe dup input of pipe to stdout exec c1 || die 

使用递归函数,尤其是在维护列表时,将帮助您简化逻辑。 你真的不必担心堆栈深度,因为你的整个地址空间都会被覆盖。

在其他新闻中,从手册页 :

在从这些系统调用之一成功返回之后,旧的和新的文件描述符可以互换使用。 它们引用相同的打开文件描述(参见open(2)),从而共享文件偏移量和文件状态标志; 例如,如果通过在其中一个描述符上使用lseek(2)修改文件偏移量,则另一个描述符的偏移量也会更改。

当你说你正在关闭管道的两端时,这意味着什么? 你真的在关闭它 – 它和你的程序打算使用的标准输入/输出。

– >多次编辑< -

正如Jonathan Leffler指出的那样,上述信息是正确的。 我用以下程序确认了它:

 #include  int main(){ dup2(0, 7); write(7, "Hey, 1\n", 7); close(0); write(7, "Hey, 2\n", 7); close(7); write(7, "Hey, 3\n", 7); } 

这导致以下输出:

 $ gcc dup2Test.c && ./a.out Hey, 1 Hey, 2 

谢谢你,乔纳森!