2017-03-15 7 views
2

1つのコマンドを実行し、出力を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); 
} 

2番目の問題は、パイプファイルを開いたままにすることです。 これは良いコーディングサンプルではありませんが、どのように動作するかを説明することだけです。

// (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 ; }