如何通过编程实现Unix命令重定向至父进程获取输出?
问题描述
我正在编写一个程序,需通过编程方式将命令重定向至另一个进程。当以参数形式接收命令时,希望父进程能获取该命令的输出。我的代码如下:
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> int main(int argc, char* argv[]) { { char msg[8]="message"; int pp[2]; if(pipe(pp)<0) { printf("Error pipe"); exit(1); } if (!fork()) { close(fd[0]); //TODO... } else { close(fd[1]); read(fd[0], msg, 8); close(fd[0]); } }
我在子进程部分遇到困惑,不知道如何执行命令并完成重定向操作。我使用pipe实现父子进程间通信,子进程已关闭不使用的管道端,但后续步骤无从下手,能否提供帮助?
解决方案
首先修正代码里的变量名不一致问题:你定义的管道是pp[2],但后续用了fd,这会导致编译错误,需要统一为pp。
子进程的核心操作是把命令的标准输出重定向到管道的写端,然后执行目标命令,具体步骤如下:
- 使用
dup2()将标准输出(STDOUT_FILENO)复制到管道的写端pp[1],这样命令的输出就会流入管道。 - 关闭管道的写端
pp[1]——因为dup2已经创建了一个指向该管道端的副本,原文件描述符不再需要。 - 调用
exec系列函数执行目标命令(比如execvp,适合处理命令行参数)。如果exec调用失败,要输出错误信息并退出子进程。
同时父进程需要等待子进程执行完毕,避免僵尸进程,并且要循环读取管道内容(因为单次read可能无法获取全部输出)。
修正后的完整代码如下:
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <errno.h> int main(int argc, char* argv[]) { // 检查是否传入了命令参数 if (argc < 2) { fprintf(stderr, "Usage: %s <command> [args...]\n", argv[0]); exit(EXIT_FAILURE); } char buf[1024]; int pp[2]; if (pipe(pp) < 0) { perror("pipe failed"); exit(EXIT_FAILURE); } pid_t pid = fork(); if (pid == -1) { perror("fork failed"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程:关闭管道读端,重定向stdout到管道写端 close(pp[0]); // 将标准输出重定向到管道写端 if (dup2(pp[1], STDOUT_FILENO) == -1) { perror("dup2 failed"); exit(EXIT_FAILURE); } // 重定向标准错误输出到管道写端(可选,如需捕获命令的错误输出) // if (dup2(pp[1], STDERR_FILENO) == -1) { // perror("dup2 stderr failed"); // exit(EXIT_FAILURE); // } // 关闭原管道写端 close(pp[1]); // 执行命令,使用argv[1]作为命令,argv+1作为参数数组 execvp(argv[1], argv + 1); // 如果execvp返回,说明执行失败 perror("execvp failed"); exit(EXIT_FAILURE); } else { // 父进程:关闭管道写端,读取子进程输出 close(pp[1]); ssize_t bytes_read; // 循环读取管道内容直到EOF while ((bytes_read = read(pp[0], buf, sizeof(buf)-1)) > 0) { buf[bytes_read] = '\0'; // 添加字符串结束符 printf("Received from child:\n%s", buf); } if (bytes_read == -1) { perror("read failed"); exit(EXIT_FAILURE); } close(pp[0]); // 等待子进程结束,避免僵尸进程 int status; waitpid(pid, &status, 0); if (WIFEXITED(status)) { printf("\nChild exited with status %d\n", WEXITSTATUS(status)); } } return 0; }
关键说明
dup2():用于复制文件描述符,这里把管道写端复制到标准输出,实现输出重定向。execvp():会加载并执行新的程序,替换当前子进程的地址空间。它接收命令名和参数数组,适合处理用户传入的命令参数。- 父进程需要循环读取管道,因为管道中的数据可能分多次传输,单次
read无法获取全部内容。 - 可选重定向
STDERR_FILENO到管道,这样父进程也能捕获命令的错误输出。
内容的提问来源于stack exchange,提问作者user20220951
相关产品推荐
相关产品推荐

