簡體   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