2017-03-15 86 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 ; }