简体   繁体   English

fork 和 pipe 错误的文件描述符错误

[英]fork and pipe bad file descriptor error

I'm trying to write a basic shell, and in order to facilitate piping, I wrote the following function, where tokens is the line to be executed, and index is the location in tokens of a pipe character (for now, pipes require whitespace on either side).我正在尝试编写一个基本的shell,为了便于管道,我编写了以下函数,其中tokens是要执行的行, index是管道字符在tokens中的位置(目前,管道需要空格两边)。 Every time I run a piped command in the shell, both commands run as expected, but fail to write to/read from the pipe with the error "Bad file descriptor".每次我在 shell 中运行管道命令时,两个命令都按预期运行,但无法写入/读取管道并显示错误“文件描述符错误”。 The reason this is perplexing is that my file redirection works perfectly, so I can't understand why it's not working with the pipe.这令人困惑的原因是我的文件重定向工作完美,所以我不明白为什么它不能与管道一起工作。 I've read the docs and looked at some example code, and I can't think of anything I'm doing wrong.我已经阅读了文档并查看了一些示例代码,但我想不出我做错了什么。 After a few hours, I'm at a loss, where did I go wrong?几个小时后,我不知所措,我哪里出错了?

int pipeit(vector<string> tokens,unsigned int index){
    //separate the entire line into two delimited by the pipe
    vector<string> firstline;
    vector<string> secondline;
    for(unsigned int i=0;i<tokens.size();i++){
        if(i==index){
            continue;
        }
        else if(i<index){
            firstline.push_back(tokens[i]);
        }
        else{
            secondline.push_back(tokens[i]);
        }
    }

    //make sure the lines aren't empty
    if(secondline.size()==0||firstline.size()==0){
      fprintf(stderr, "ERROR, expected at least one command at both ends of pipe\n");
    }

    //open a pipe, check that it was successfully created
    int pip[2];
    if(pipe(pip)<0){
      perror("pipe failure");
      return -1;
    }

    //attempt to fork
    int parentstatus=0;
    int childstatus=0;
    switch(fork()){

      //fork failed, close the pipe and return -1 (failure)
      case -1:
        {
          close(pip[0]);
          close(pip[1]);
          perror("fork failure");
          return -1;
        }

      //pid of 0 indicates this is the child process
      case 0:
        {
          //close the write end of the pipe and redirect stdin to the read end
          close(pip[0]);
          int stdIn=dup(0);
          dup2(pip[1],0);

          //once redirect is done, can close the other end of the pipe
          close(pip[1]);

          //parse the second line as a list of commands (not important for question)
          //then restore stdin, close the old file descriptor pointing to the pipe
          execute_line(secondline,builtins);
          dup2(stdIn,0);
          close(stdIn);
          break;
        }

      //pid other than 0 indicates this is the parent process
      default:
        {
          //close the read end of the pipe
          close(pip[1]);

          //redirect stdout to the write end of the pipe
          int stdOut=dup(1);
          dup2(pip[0],1);
          close(pip[0]);

          //execute this line (not important for question)
          parentstatus=execute_line(firstline,builtins);

          //restore stdout and close the temporary fd pointing to the pipe
          dup2(stdOut,1);
          close(stdOut);

          //wait for child process to exit and store it's return value in 'status' (then childstatus)
          int status;
          wait(&status);
          childstatus=status;
          break;
        }
    }

    //return a combination of the parent and child's return status
    //(not standard, I know, just easy and irrelevant for the question)
    return childstatus & parentstatus;
  }

tokens is just a space-delimited std::vector<string> that contains the commands to be executed (yeah you need to pad the '|' with spaces for this to work, don't worry about that just yet) and index is the place in the list where the '|' tokens只是一个以空格分隔的std::vector<string> ,其中包含要执行的命令(是的,您需要用空格填充 '|' 才能使其工作,暂时不要担心)并且index是列表中“|”所在的位置character was found, to make things easier.找到了性格,让事情变得更容易。 For the purposes of a runnable source file, just paste the above function definition at the bottom of:出于可运行源文件的目的,只需将上述函数定义粘贴到以下内容的底部:

#include <unistd.h> //pipe, dup2, fork
#include <iostream>
#include <string>

int builtins = 0xf00; //not what this actually is, but that doesn't matter atm

using namespace std;

int pipeit(vector<string> tokens, unsigned int index);

void execute_line(vector<string> cmds, int biltins){
    cout << "Executing: " << endl;
    for(unsigned int i = 0; i < cmds.size(); ++i){
        cout<<cmds[i]<< " ";
    }
    cout << endl;
}

int main(){
    vector<string> cmds;
    cmds.push_back(new string("cmd1"));
    cmds.push_back(new string("|"));
    cmds.push_back(new string("cmd2"));
    return pipeit(cmds, 1);
}

The problem is that I was reading from the write end of the pipe and writing to the read end.问题是我从管道的写入端读取并写入读取端。 Whenever you use pipe(my_pipe) , my_pipe[0] is only for reading, and my_pipe[1] is only for writing.无论何时使用pipe(my_pipe)my_pipe[0]用于读取,而my_pipe[1]用于写入。 This doesn't mean my code works for infinite piping, for anybody else looking this up, but it does single pipes now.这并不意味着我的代码适用于无限管道,其他任何人都可以查看它,但它现在可以使用单个管道。
CTC: IRC user C-- CTC:IRC 用户 C--

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM