2017-03-15 85 views
2

我想創建一個函數,它運行一個命令,然後將輸出管道輸出到第二個命令並運行它。我在無限循環中運行該函數。問題是,該函數首次運行,但之後沒有顯示任何內容。 例如,當我運行ls | wc -l時,它第一次顯示正確的結果,但是當我運行它之後,我得不到輸出。使用fork和exec管道輸出後不顯示輸出

這裏是我的功能(解析是另一個函數處理):

void system_pipe(std::string command1, std::string command2) 
{ 
    int status; 
    int fd[2]; 
    int fd2[2]; 
    pipe(fd); 

    int pid = fork(); 
    // Child process. 
    if (pid == 0) 
    { 
     std::shared_ptr<char> temp = string_to_char(command1); 
     char *name[] = {"/bin/bash", "-c", temp.get(), NULL}; 

     close(fd[0]); 
     dup2(fd[1], 1); 
     execvp(name[0], name); 

     exit(EXIT_FAILURE); 
    } 
    // Parent process. 
    else 
    { 
     std::shared_ptr<char> temp = string_to_char(command2); 
     char *name[] = {"/bin/bash", "-c", temp.get(), NULL}; 

     close(fd[1]); 
     dup2(fd[0], 0); 
     waitpid(pid, &status, 0); 
     //my_system(command2); 

     // Fork and exec a new process here. 
     int pid2 = fork(); 
     if (pid2 == 0) 
     { 
      execvp(name[0], name); 
      exit(EXIT_FAILURE); 
     } 
     else 
     { 
      waitpid(pid2, NULL, 0); 
     } 
    } 

    if (status) 
     std::cout << "Bad" << std::endl; 
} 

我這樣調用該函數:

while(true) 
{ 
    string line; 
    getline(cin, line); 
    pair<string, string> commands = parse(line); 
    system_pipe(commands.first, commands.second); 
} 

爲什麼功能只有正確地在第一循環的工作?之後有什麼變化?

回答

1
else 
{ 
     std::shared_ptr<char> temp = string_to_char(command2); 
     char *name[] = {"/bin/bash", "-c", temp.get(), NULL}; 

     close(fd[1]); 
     dup2(fd[0], 0); 
     waitpid(pid, &status, 0); 
     //my_system(command2); 

我相信這不是你的意圖。 dup2必須在兒童中被調用。

int pid2 = fork(); 
if (pid2 == 0) 
{ 
    dup2(fd[0], 0); // here. 
    execvp(name[0], name); 
    exit(EXIT_FAILURE); 
} 

第二個問題是您打開管道文件。 這不是一個好的編碼示例,但它只是爲了說明它應該如何工作。

// (g++ -std=c++11 ) 
// type `ls | grep file.cxx` 
#include <iostream> 
#include <string> 
#include <cstring> 
#include <array> 
#include <memory> 

#include <sys/wait.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

void replace_with (std::string command) 
{ 
    char exec_name [] = "bash" , arg [] = "-c" ; 
    char * line [] = { exec_name , arg , &command[ 0 ] , nullptr } ; 
    execvp(exec_name , line) ; 
} 

void pipeline (const std::string& command0 , const std::string& command1) 
{ 
    std::array< int , 2 > pipe_fd ; enum { READ_END , WRITE_END } ; 

    if (pipe(pipe_fd.data())) throw std::runtime_error("can't create a pipe") ; 

    int id = fork() ; 
    if (id < 0) { for (auto each : pipe_fd) close(each) ; 
        throw std::runtime_error("can't create a child") ; } 

    if (! id) /* child */ 
    { 
     close(pipe_fd[ READ_END ]) ; 
     dup2(pipe_fd[ WRITE_END ] , STDOUT_FILENO) ; 
     close(pipe_fd[ WRITE_END ]) ; // 

     replace_with(command0) ; 
    } 
    else /* parent */ 
    { 
     close(pipe_fd[ WRITE_END ]) ; 
     waitpid(id , nullptr , 0) ; 
     int id_second = fork() ; 
     if (id_second > 0) waitpid(id_second , nullptr , 0) ; 
     else if (! id_second) /* child */ 
     { 
      dup2(pipe_fd[ READ_END ] , STDIN_FILENO) ; 
      close(pipe_fd[ READ_END ]) ; // 
      replace_with(command1) ; 
     } 

     close(pipe_fd[ READ_END ]) ; 
    } 
} 

int main() try 
{ 
    while (true) 
    { 
     std::string command0 , command1 ; 
     getline(std::cin , command0 , '|') ; 
     getline(std::cin , command1) ; 
     pipeline(command0 , command1) ; 
    } 

} catch (const std::runtime_error& e) 
    { std::cerr << e.what() ; return - 1 ; }