繁体   English   中英

为什么不能通过两个execl调用传递输出?

[英]why can't I pipe output from both execl calls?

可能重复:

我一直在尝试使用dup / dup2在Linux中学习管道,并在最近3天进行了分叉。 我想我掌握了这个要诀,但是当我从子进程中调用两个不同的程序时,看来我只是从第一个调用的程序中捕获输出。 我不明白为什么会这样和/或我做错了什么。 这是我的主要问题。

编辑:我认为可能的解决方案是派生另一个孩子并使用dup2设置管道,但是我只是想知道为什么下面的代码不起作用。 我的意思是,我希望从第一个execl调用捕获stderr,从第二个execl调用捕获stdout。 这似乎没有发生。

我的第二个问题是我是否正确打开和关闭管道。 如果没有,我想知道我需要添加/删除/更改。

这是我的代码:

#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <sys/wait.h>

#define READ_END 0
#define WRITE_END 1

void parentProc(int* stdoutpipe, int* stderrpipe);
void childProc(int* stdoutpipe, int* stderrpipe);

int main(){
    pid_t pid;
    int status;

    int stdoutpipe[2]; // pipe
    int stderrpipe[2]; // pipe

    // create a pipe
    if (pipe(stdoutpipe) || pipe(stderrpipe)){
        std::cerr << "Pipe failed." << std::endl;
        return EXIT_FAILURE;
    }

    // fork a child
    pid = fork();
    if (pid < 0) {
        std::cerr << "Fork failed." << std::endl;
        return EXIT_FAILURE;
    } 
    // child process
    else if (pid == 0){
        childProc(stdoutpipe, stderrpipe);  

    }
    // parent process
    else {
        std::cout<< "waitpid: " << waitpid(pid, &status, 0)
             <<'\n'<<std::endl;
        parentProc(stdoutpipe, stderrpipe);
    }

    return 0;
}



void childProc(int* stdoutpipe, int* stderrpipe){
    dup2(stdoutpipe[WRITE_END], STDOUT_FILENO);
    close(stdoutpipe[READ_END]);

    dup2(stderrpipe[WRITE_END], STDERR_FILENO);
    close(stderrpipe[READ_END]);

    execl("/bin/bash", "/bin/bash", "foo", NULL);
    execl("/bin/ls", "ls", "-1", (char *)0);

    //  execl("/home/me/outerr", "outerr", "-1", (char *)0);

    //char * msg = "Hello from stdout";
    //std::cout << msg;

    //msg = "Hello from stderr!";
    //std::cerr << msg << std::endl;

    // close write end now?
}

void parentProc(int* stdoutpipe, int* stderrpipe){
    close(stdoutpipe[WRITE_END]);
    close(stderrpipe[WRITE_END]);

    char buffer[256];
    char buffer2[256];
    read(stdoutpipe[READ_END], buffer, sizeof(buffer));
    std::cout << "stdout: " << buffer << std::endl;

    read(stderrpipe[READ_END], buffer2, sizeof(buffer));
    std::cout << "stderr: " << buffer2 << std::endl;

    // close read end now?
}

运行此命令时,将得到以下输出:

yfp> g++ selectTest3.cpp; ./a.out 
waitpid: 21423

stdout: hB�(6
stderr: foo: line 1: -bash:: command not found

“外部”二进制文件的源代码(上面已注释)很简单:

#include <iostream>

int main(){
    std::cout << "Hello from stdout" << std::endl;
    std::cerr << "Hello from stderr!" << std::endl;
    return 0;
}

当我调用“ outerr”而不是ls或“ foo”时,将得到以下输出,这是我期望的:

yfp> g++ selectTest3.cpp; ./a.out 
waitpid: 21439

stdout: Hello from stdout

stderr: Hello from stderr!

execl

一旦成功调用exec系列中的execl或任何其他函数,新进程将完全覆盖原始进程。 这意味着新过程永远不会“返回”到旧过程。 如果您连续有两个execl调用,则第二个execl的唯一方法是第一个失败。

为了连续运行两个不同的命令,您必须fork一个孩子来运行第一个命令, waitfork另一个孩子来运行第二个命令,然后(可选)也wait第二个孩子。

read

read系统调用不会附加终止的null,因此通常您需要查看返回值,该值告诉您实际读取的字节数。 然后将以下字符设置为null以获取C字符串,或将范围构造函数用于std::string

在管道上

现在,您正在使用waitpid等待子进程已经完成, 然后从管道中读取。 这样做的问题是,如果子进程产生大量输出,则它将阻塞,因为管道已满并且父进程没有从中读取数据。 结果将导致死锁,因为子级等待父级读取,而父级等待子级终止。

您应该做的是使用select等待输入到达孩子的stdout或孩子的stderr 输入到达时,请阅读; 这将允许孩子继续。 当子进程死亡时,您会知道,因为两者都将获得文件结尾。 然后,您可以安全地调用waitwaitpid

exec系列功能将当前的过程映像替换为新的过程映像。 执行时

execl("/bin/bash", "/bin/bash", "foo", NULL);

当前进程中的代码将不再执行。 这就是为什么您永远看不到执行结果的原因

execl("/bin/ls", "ls", "-1", (char *)0);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM