You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过编程实现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。

子进程的核心操作是把命令的标准输出重定向到管道的写端,然后执行目标命令,具体步骤如下:

  1. 使用dup2()将标准输出(STDOUT_FILENO)复制到管道的写端pp[1],这样命令的输出就会流入管道。
  2. 关闭管道的写端pp[1]——因为dup2已经创建了一个指向该管道端的副本,原文件描述符不再需要。
  3. 调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 05:35:50