如何解决如何在 C++ 中“链接”管道超过 2 个管道?目前我在第二个命令中从 Bash 收到错误的文件描述符错误
为了扩展这一点,当我有 3 个单独的进程时,我指的是链式管道: 进程 1 写入进程 2, 进程 2 从进程 1 读取并写入进程 3, 进程 3 从进程 2 读取数据,然后完成。
我特别想在 C++ 编写的 bash shell 中处理复杂的命令。所以我会用它来执行一组这样的命令,这些命令都相互通信:
ls |排序 | grep“退出”
其中进程 1 正在执行 ls 并且其标准输出通过管道等写入进程 2。
我已经在为一个项目编写代码来解决这个问题,只是想知道我的方法是否正确,就像现在刚刚执行 ls | 的 2 个命令调用一样。 grep "exit" 我收到 bash 错误 "grep: (standard input): Bad file descriptor"
//Block for when the userInput is a complex command
else{
if (debug)
printf("Complex command: %s\n",userInput.c_str());
vector<char*> commandsVect = splitCString(const_cast<char*>(userInput.c_str()),const_cast<char*>( delimVertPipe.c_str()));
if (debug)
printVect(commandsVect);
if (pipe(fileDescriptor) == -1){
fprintf(stderr,"Pipe failed for command %s\n",userInput.c_str());
return 1;
}
for (int i = 0; i < commandsVect.size(); ++i) {
vector<char*> tokens = splitCString(const_cast<char*>(commandsVect[i]),const_cast<char*>( delimSpace.c_str()));
printf("Commands vect size is %ld\n",commandsVect.size());
printf("Parsing command \'%s\'\n",commandsVect[i]);
if (debug) {
printVect(tokens);
}
procID = fork();
//Block for the first command
if (i == 0){
if (procID < 0){
fprintf(stderr,"Fork number %d in the complex command \'%s\' failed\n",i+1,userInput.c_str());
return 1;
}
//Child process
else if (procID == 0){
//close(fileDescriptor[READ_END]);
close(STDOUT_FILENO);
//Links the write end of the pipe to the STDOUT
dup2(fileDescriptor[WRITE_END],1);
close(fileDescriptor[READ_END]);
close(fileDescriptor[WRITE_END]);
tokens.push_back(nullptr); //execvp() arg array needs a NULL pointer at the end
if ( execvp(tokens[0],tokens.data()) < 0 ) {
fprintf( stderr,"execvp() call failed for the command \'%s\' inside the input string \'%s\'\n",commandsVect[i],userInput.c_str() );
return 1;
}
exit(1);
}
//Parent process
else{
close(fileDescriptor[READ_END]);
close(fileDescriptor[WRITE_END]);
wait(NULL);
}
}
//Block for the very last command,which will pipe input from the previous
else if (i == commandsVect.size() - 1){
if (procID < 0){
fprintf(stderr,userInput.c_str());
return 1;
}
//Child process
else if (procID == 0){
//close(fileDescriptor[WRITE_END]);
close(STDIN_FILENO);
//Links the read end of the pipe to the STDIN
dup2(fileDescriptor[READ_END],0);
close(fileDescriptor[WRITE_END]);
close(fileDescriptor[READ_END]);
tokens.push_back(nullptr); //execvp() arg array needs a NULL pointer at the end
if ( execvp(tokens[0],userInput.c_str() );
return 1;
}
exit(1);
}
//Parent process
else{
close(fileDescriptor[READ_END]);
close(fileDescriptor[WRITE_END]);
wait(NULL);
}
}
//To note for StackOverflow,this block of code is never executed since I am only ever calling a 2 chained command like ls|grep "exit"
//Block for the middle commands. (Will pipe input from previous,and output to the next)
else{
printf("GOING THROUGH BAD CODE");
continue;
if (procID < 0){
fprintf(stderr,userInput.c_str());
return 1;
}
//Child process
else if (procID == 0){
exit(1);
}
//Parent process
else{
wait(NULL);
}
}
}
close(fileDescriptor[READ_END]);
close(fileDescriptor[WRITE_END]);
}
解决方法
对于较大的应用程序,这可能是不可能的,但是您可以通过让 shell 管理管道来简化事情。将 P1(进程一)、P2 和 P3 写为三个独立的可执行文件。每个程序都可以从标准输入读取并写入标准输出,而不是在管道上进行 IO。简单的。执行 - 让 bash 或您使用的任何 shell 通过将它们称为...
$P1 | P2 | P3;
在幕后,您的 shell 正在执行您在 C++ 中所做的工作(仅成功?)。它为 P1 创建一个管道,它作为 stdin 传递给 exec 以在分叉后启动 P1。它为 P2 创建一个输入和输出管道,并以相同的方式适当地绑定 stdin 和 stdout - 在 fork 之后启动 P2 时传递给 exec。 P3 只得到一个标准输入管道,它的标准输出流像往常一样直接进入控制台。它不像在 C++ 中那样性感,但它非常健壮 - 几乎可以保证工作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。