如何将exec系统调用的输出保存到pipe()对应的父进程管道中
实现逻辑说明
fork创建的子进程会默认继承父进程所有打开的文件描述符,管道本质也是特殊的文件描述符,因此可以通过文件描述符重定向的方式,让exec启动的目标程序把输出写入管道。
具体实现步骤
- 在调用
fork()之前先创建管道,得到读端pipefd[0]、写端pipefd[1]两个文件描述符,两个描述符会被后续fork出的子进程继承 - fork完成后分别在父子进程关闭不需要的管道端:
- 父进程关闭写端
pipefd[1],仅保留读端用于读取子进程输出 - 子进程关闭读端
pipefd[0],仅保留写端用于写入输出
- 父进程关闭写端
- 子进程调用exec前,使用
dup2()系统调用把管道写端复制到标准输出STDOUT_FILENO(文件描述符1),如果需要捕获标准错误也可以同步复制到STDERR_FILENO(文件描述符2) - 子进程执行exec启动目标C程序,目标程序的标准输出/标准错误默认会写入管道写端,父进程直接从
pipefd[0]读取数据即可
代码示例
主程序(父进程代码)
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main() { int pipefd[2]; // 创建管道 if (pipe(pipefd) == -1) { perror("pipe创建失败"); return 1; } pid_t pid = fork(); if (pid == -1) { perror("fork创建失败"); return 1; } if (pid == 0) { // 子进程逻辑 close(pipefd[0]); // 关闭不需要的读端 // 把管道写端重定向到标准输出 dup2(pipefd[1], STDOUT_FILENO); // 可选:同步捕获标准错误就加上这行 // dup2(pipefd[1], STDERR_FILENO); close(pipefd[1]); // 重定向完成后原管道写端可关闭 // exec执行目标程序,target为编译后的目标程序文件名 execl("./target", "target", NULL); perror("execl调用失败"); return 1; } else { // 父进程逻辑 close(pipefd[1]); // 关闭不需要的写端 char buf[1024]; ssize_t read_len; // 从管道读端读取子进程输出 while ((read_len = read(pipefd[0], buf, sizeof(buf)-1)) > 0) { buf[read_len] = '\0'; printf("捕获到子进程输出:%s", buf); } close(pipefd[0]); wait(NULL); // 等待子进程回收 return 0; } }
目标程序(被exec启动的C程序,编译后命名为target)
#include <stdio.h> int main() { printf("这是目标程序输出的内容\n"); fprintf(stderr, "这是目标程序的标准错误输出\n"); return 0; }
注意事项
- 不需要的管道端必须及时关闭,否则读端的
read()会一直阻塞无法收到EOF信号 - exec调用会替换子进程的整个地址空间,但默认不会关闭继承的文件描述符,只要没有给管道描述符设置
FD_CLOEXEC标志,exec执行后管道描述符仍然可用 - 如果目标程序不需要通过标准输出写管道,也可以直接把管道写端的文件描述符作为启动参数传给exec启动的程序,目标程序直接向该描述符写数据即可
内容的提问来源于stack exchange,提问作者Yerni
相关产品推荐
相关产品推荐

