C语言实现多Linux命令管道处理:修复仅执行前两条命令的问题
问题分析与修复方案
你的代码核心问题出在循环逻辑上:每次fork后直接调用execvp,进程执行完命令就退出了,第一次循环(i=0)执行完ls和head后,根本不会进入第二次循环处理tail。而且你错误地在单次循环里同时处理相邻两个命令,没形成正确的管道链式传递。
修复后的代码
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main(void) { char **cmds[3]; char *c1[] = { "ls", "-l", "/etc", NULL }; char *c2[] = { "head", "-n", "10", NULL }; char *c3[] = { "tail", "-n", "5", NULL }; cmds[0] = c1; cmds[1] = c2; cmds[2] = c3; int num_cmds = 3; int infd = 0; // 初始输入为标准输入 int i; for (i = 0; i < num_cmds; i++) { int fd[2]; // 最后一个命令不需要创建管道 if (i < num_cmds - 1) { pipe(fd); } pid_t pid = fork(); if (pid == 0) { // 重定向输入到之前的infd if (infd != 0) { dup2(infd, 0); close(infd); } // 如果不是最后一个命令,重定向输出到管道写端 if (i < num_cmds - 1) { dup2(fd[1], 1); close(fd[0]); close(fd[1]); } // 执行当前命令 execvp(cmds[i][0], cmds[i]); // 如果exec失败,打印错误 perror("execvp failed"); _exit(1); } else if (pid > 0) { // 父进程关闭不需要的文件描述符 if (infd != 0) { close(infd); } if (i < num_cmds - 1) { close(fd[1]); infd = fd[0]; // 更新下一个命令的输入为当前管道读端 } } else { perror("fork failed"); return 1; } } // 等待所有子进程结束 while (wait(NULL) != -1); return 0; }
关键改动说明
- 链式管道传递:维护一个
infd变量,记录当前命令的输入来源,初始是标准输入。每处理一个命令(除最后一个),创建管道,把当前命令的输出重定向到管道写端,下一个命令的输入从管道读端获取。 - 分阶段处理命令:每个循环只处理当前命令,最后一个命令直接使用之前的管道读端作为输入,不需要创建新管道。
- 正确关闭文件描述符:父进程和子进程都要关闭不需要的管道端,避免资源泄漏和管道阻塞。
- 错误处理:增加
perror处理execvp和fork的失败情况,便于调试。
内容的提问来源于stack exchange,提问作者American Tom
相关产品推荐
相关产品推荐

