使用 fork 和 exec 管道后不显示输出
output not displaying after piping with fork and exec
我正在尝试创建一个函数,该函数 运行 执行一个命令,然后将输出通过管道传输到第二个命令,然后 运行 执行该命令。我在无限循环中 运行 设置函数。问题是,该功能第一次运行,但之后没有显示任何内容。
例如,当我 运行 ls | wc -l
时,第一次它显示正确的结果,但是当我 运行 之后我没有输出。
这是我的函数(解析在另一个函数中处理):
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);
}
为什么函数只在第一个循环中正确运行?之后发生了什么变化?
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);
我相信那不是你的意图。必须在 child 中调用 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 ; }
我正在尝试创建一个函数,该函数 运行 执行一个命令,然后将输出通过管道传输到第二个命令,然后 运行 执行该命令。我在无限循环中 运行 设置函数。问题是,该功能第一次运行,但之后没有显示任何内容。
例如,当我 运行 ls | wc -l
时,第一次它显示正确的结果,但是当我 运行 之后我没有输出。
这是我的函数(解析在另一个函数中处理):
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);
}
为什么函数只在第一个循环中正确运行?之后发生了什么变化?
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);
我相信那不是你的意图。必须在 child 中调用 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 ; }