Unix C中父子进程通过管道通信及命令执行结果获取问题
子进程执行命令并捕获输出的管道实现方案
实现逻辑
程序按以下步骤实现功能:
- 先创建无名管道
- 调用
fork()创建子进程 - 父子进程分别关闭管道中自身不需要的文件描述符
- 子进程调用
dup2()将管道写端fd[1]复制到标准输出文件描述符,完成输出重定向,随后执行ls -a命令,命令执行产生的标准输出会自动写入管道 - 父进程从管道读端
fd[0]循环读取数据,将读取到的命令输出打印到终端
相关背景知识
Linux系统中每个进程默认打开3个标准文件描述符:
- 标准输入(stdin):文件描述符为0,默认对应键盘输入,抽象为文件后可简化Shell脚本编写
- 标准输出(stdout):文件描述符为1,默认对应进程运行的终端窗口,抽象为文件后可简化程序与脚本开发
- 标准错误(stderr):文件描述符为2,默认输出位置与标准输出一致,对应进程运行的终端窗口
核心问题解决说明
你遇到的exec系列函数执行后后续代码不运行的问题是正常特性:exec会用新程序的内存镜像替换当前进程的内存镜像,原有进程的后续代码都会失效。
我们不需要在exec之后编写写入管道的逻辑,只需要在调用exec之前完成标准输出到管道的重定向即可:执行新程序后,所有输出到标准输出的内容会自动写入管道,无需额外编码。
可运行完整代码
#include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #define BUFFER_SIZE 1024 #define READ_END 0 #define WRITE_END 1 int main(void) { char readbuf[BUFFER_SIZE]; int fd[2]; pid_t pid; /* 创建管道 */ if (pipe(fd) == -1) { fprintf(stderr, "Pipe failed\n"); return 1; } /* fork子进程 */ pid = fork(); if (pid < 0) { fprintf(stderr, "Fork Failed\n"); return 1; } if (pid > 0) { /* 父进程:读管道内容 */ /* 关闭不需要的写端 */ close(fd[WRITE_END]); /* 循环读取管道数据直到读完 */ ssize_t n; while ((n = read(fd[READ_END], readbuf, BUFFER_SIZE - 1)) > 0) { readbuf[n] = '\0'; printf("%s", readbuf); } close(fd[READ_END]); /* 等待子进程退出避免僵尸进程 */ wait(NULL); } else { /* 子进程:执行命令输出到管道 */ /* 关闭不需要的读端 */ close(fd[READ_END]); /* 将标准输出重定向到管道写端 */ dup2(fd[WRITE_END], STDOUT_FILENO); /* 重定向后关闭原有管道写端 */ close(fd[WRITE_END]); /* 执行ls -a命令 */ execlp("ls", "ls", "-a", NULL); /* 如果exec执行失败才会走到下面的代码 */ perror("execlp failed"); exit(EXIT_FAILURE); } return 0; }
内容的提问来源于stack exchange,提问作者ayaz
相关产品推荐
相关产品推荐

