我在要用C++创建的Shell上的Pipelines遇到问题。我试图首先在两个命令之间进行管道传输,当我运行程序时,它会按照它应该的方式进行管道传输。但它不会结束我的文件或程序返回命令行。这是一个输入所有内容而不显示错误的无限循环。
管道的代码如下:
if(countpipes!=0)
{
pid_t pid;
int pipefd[2];
pipe(pipefd);
for(int j=0; j<commands.size(); j++)
{ //cout<<endl<<"IT of "<<j<<" "<<commands[j]<<endl;
vector<string> all_commands = split(commands[j]);
vector<string> next_commands;
if(j!=commands.size()-1)
{ //cout<<"Piped once"<<endl;
pipe(pipefd);
}
if(j+1<commands.size())
{
next_commands = split(commands[j+1]);
}
char* arguments[all_commands.size()+1];
arguments[all_commands.size()] = NULL;
for (int k = 0; k < all_commands.size(); k++)
{
arguments[k] = (char*)all_commands[k].c_str();
}
char* next_arguments[next_commands.size()+1];
next_arguments[next_commands.size()] = NULL;
for (int l = 0; l < next_commands.size(); l++)
{
next_arguments[l] = (char*)next_commands[l].c_str();
}
pid = fork();
//cout<<"Child: "<<pid<<endl;
if (pid < 0) {
// Showing an error
perror("fork");
exit(1);
}
if (pid == 0) {
// Child Process
if(j==0)
{
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
int result2;
result2 = execvp(arguments[0], arguments);
if(result2 < 0)
{
perror("execvp");
exit(1);
}
}
else
{
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
int result;
result = execvp(arguments[0], arguments);
if (result < 0) {
perror("execvp");
exit(1);
}
}
}
else {
//cout<<"Wait pid"<<endl;
wait(NULL);
//cout<<"Wait after pid"<<endl;
}
}
}
我使用的是一个字符串向量,它接受每个命令。管道的最终输出是这样的,让我永远介绍我想要的任何文本:https://i.stack.imgur.com/HbG4R.jpg
按照设置fork/exec的方式,每个子级将只连接到一个管道——第一个子级连接到管道的写入端(stdout(,随后的每个子级连接(stdin(到管道的读取端。这不适用于管道中的3个子级以上,因为中间的子级需要连接到两个(不同的(管道——stdin连接到一个管道的读取端,stdout连接到另一管道的写入端。
您没有关闭父级中的管道末端,因此从管道中读取的任何子级都不会看到EOF——即使上一个正在向管道写入的子级退出,父级仍将打开写入末端。
您似乎还创建了一个next_agruments
argv,但从未使用过,这是无用的,可能表明您的设计中存在一些混乱。
你想要的伪代码:
int prev_out = -1, pipefds[2];
for (each command in the pipeline) {
if (not last command)
pipe(pipefds);
if ((child[i++] = fork()) == 0) {
// child
if (prev_out >= 0)
dup2(prev_out, 0);
if (not last command) {
dup2(pipefd[1], 1);
close(pipefd[0]); }
execvp(...
} else {
// parent
if (prev_out >= 0)
close(prev_out);
if (not last command) {
close(pipefd[1]);
prev_out = pipe_fd[0]; }
}
}
// now wait for the children.
你需要在每对孩子之间用一根管子把他们连接起来。在分叉子对象之后,您需要关闭父对象中的所有管道fd。你不想等待任何一个孩子,直到你创造了所有的孩子。