C语言如何在fork创建的子进程中获取并打印exec()执行输出
问题说明
你当前代码存在两个核心问题:
execlp传参错误:exec族函数的参数列表中,第一个可变参数必须对应被执行程序的argv[0](惯例为程序自身名称),你漏传了date作为首个参数,导致date命令无法识别+%H:%M:%S格式参数,执行会直接失败。- exec类函数的核心逻辑是用新程序的映像完全替换当前进程的地址空间,一旦
exec调用成功,当前进程原有代码会全部消失,直接运行新程序,根本不可能在原有子进程的代码逻辑中捕获exec后程序的输出。如果需要在子进程内获取被执行命令的输出内容再自定义打印,不能直接在子进程中调用exec,需要通过管道重定向被执行程序的标准输出,再读取输出内容。
另外你的父进程没有回收子进程资源,运行时会产生僵尸进程。
实现方案
如果你的需求只是让子进程执行date命令并输出时间,不需要自定义处理输出内容,只需要修正execlp的参数,同时在父进程中回收子进程即可。
如果需要在子进程内部获取命令的输出内容,自行完成打印后再退出,推荐两种实现方式:
方式1:使用popen快速实现(最简便)
popen是标准库封装好的函数,会自动完成管道创建、子进程fork、程序exec、输出重定向的全流程,你只需要读取返回的文件流就能拿到命令输出。
修正后的完整代码如下:
#include <stdio.h> #include <time.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> int main() { time_t endwait; time_t start = time(NULL); time_t seconds = 60; endwait = start + seconds; while (start < endwait) { pid_t pid = fork(); if(pid == 0){ // 子进程逻辑:用popen执行date命令,读取输出 FILE *fp = popen("date +%H:%M:%S", "r"); if (fp == NULL) { perror("popen failed"); _exit(1); } char buf[64] = {0}; // 读取命令输出 if (fgets(buf, sizeof(buf), fp) != NULL) { printf("子进程获取到exec执行结果:%s", buf); } pclose(fp); _exit(0); // 打印完成后终止子进程 } // 父进程回收子进程资源,避免僵尸进程 waitpid(pid, NULL, 0); sleep(5); start = time(NULL); } printf("end time is %s", ctime(&endwait)); return 0; }
方式2:手动创建管道实现(便于理解原理)
如果要手动实现逻辑,需要在子进程中创建管道,再fork孙进程执行date命令,将孙进程的标准输出重定向到管道写端,子进程从管道读端读取输出内容即可:
#include <stdio.h> #include <time.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> #include <string.h> int main() { time_t endwait; time_t start = time(NULL); time_t seconds = 60; endwait = start + seconds; while (start < endwait) { pid_t pid = fork(); if(pid == 0){ int pipe_fd[2]; if (pipe(pipe_fd) == -1) { perror("pipe create failed"); _exit(1); } pid_t grand_pid = fork(); if (grand_pid == 0) { // 孙进程:关闭读端,重定向stdout到管道写端,执行date close(pipe_fd[0]); dup2(pipe_fd[1], STDOUT_FILENO); close(pipe_fd[1]); execlp("date", "date", "+%H:%M:%S", NULL); _exit(1); } // 子进程:关闭写端,读取管道内容 close(pipe_fd[1]); char buf[64] = {0}; read(pipe_fd[0], buf, sizeof(buf)-1); close(pipe_fd[0]); // 回收孙进程 waitpid(grand_pid, NULL, 0); printf("子进程获取到exec执行结果:%s", buf); _exit(0); } waitpid(pid, NULL, 0); sleep(5); start = time(NULL); } printf("end time is %s", ctime(&endwait)); return 0; }
补充说明
如果你不需要在子进程代码中额外处理输出,只是要date命令自己打印结果,那子进程里的逻辑可以简化为修正参数的execlp调用即可,不需要管道:
if(pid == 0){ // 注意第二个参数是argv[0],传"date" execlp("date", "date", "+%H:%M:%S", NULL); // exec只有失败才会走到这里 perror("execlp failed"); _exit(1); }
内容的提问来源于stack exchange,提问作者Timmske
相关产品推荐
相关产品推荐

