写我自己的外壳......卡在管道上?

101*_*101 16 c++ unix shell pipe

在过去的几天里,我一直在尝试编写自己的shell实现,但我似乎一直在努力让管道正常工作.我能够解析一条线并分开管道之间的命令(例如:ls | sort),但似乎无法将它们从一个管道输入到另一个管道输入.

我想我只是不明白如何正确使用dup2()和管道.

我现在已经包含了仍然失败的代码... :(因此卡住了...

void forkAndExecute( char* arrayOfWords[] , vector<pid_t> *vectorOfPIDs , bool hasNextCmd , bool hasPrevCmd) {

int fd[ 2 ];
pid_t pid;

if( hasNextCmd ){
    pipe(fd);
}

pid = fork();

//error if PID < 0
if( pid < 0 ) {
    cerr << ">>> fork failed >>>" << endl;
    exit(-1);
}
//child process if PID == 0
else if( pid == 0 ) {
    if ( hasPrevCmd ){
        dup2(fd[0] , 0);
        close(fd[0]);
        close(fd[1]);

    }
    if ( hasNextCmd ){
        dup2(fd[1],1);
        close(fd[0]);
        close(fd[1]);
    }
    execvp( arrayOfWords[0] , arrayOfWords );
    cout << ">>> command not found >>>" << endl;
    //if logic reaches here, exec failed
    exit(0);
} 
//parent process
else{
    close(fd[0]);
    close(fd[1]);
    //if( ! isLastCmd ){

    //}
    vectorOfPIDs->push_back(pid);
}
Run Code Online (Sandbox Code Playgroud)

}

Jos*_*ley 10

第一个建议:符号常量优于魔术数字.

const int PIPE_READ = 0;
const int PIPE_WRITE = 1;
int fd[2];
pipe(fd);
// Now you can refer to fd[PIPE_READ] and fd[PIPE_WRITE].
Run Code Online (Sandbox Code Playgroud)

第二个建议:退一步思考你想要完​​成的事情.

您希望生成两个进程,第一个进程的stdout连接到第二个进程的stdin.对?

因此,在C中,这意味着您需要进行调用pipe,传递fd[PIPE_WRITE]给第一个子进程,该进程将为dup21,并传递fd[PIPE_READ]给第二个子进程,该进程将为dup20.

简单地看一下forkAndExecute's原型就表明它无法做到:

void forkAndExecute( char* arrayOfWords[] , vector *vectorOfPIDs , 
    bool hasNextCmd , bool hasPrevCmd);
Run Code Online (Sandbox Code Playgroud)

它只处理一个命令,并且从查看该参数列表开始,除非它转向邪恶的全局变量,否则它无法从其PrevCmd接收文件描述符或从其NextCmd接收文件描述符.

考虑如何管理所需的文件描述符,并重新设计forkAndExecute以便能够使用它们.


JB.*_*JB. 6

一般过程会为此基本进程添加错误处理(伪代码):

pipe(fds)
if (fork() is child) {
  dup2(fds[1], 1)
  close(fds[0])
  close(fds[1])
  exec("ls")
}
if (fork() is child) {
  dup2(fds[0], 0)
  close(fds[0])
  close(fds[1])
  exec("sort")
}
close(fds[0])
close(fds[1])
wait()
Run Code Online (Sandbox Code Playgroud)

首先创建管道.然后派生子进程,以便继承它.将文件描述符重新映射为0(stdin)和1(stdout),以便进程读取和写入适当的位置.关闭任何剩余的文件描述符,您不希望子进程在工作完成时查看或阻止.执行实际的子进程.等待他们完成,你就完成了!


wak*_*fus 6

好的,这对我有用.希望这可以帮助你:

/************************
function: void pipeCommand(char** cmd1, char** cmd2)
comment: This pipes the output of cmd1 into cmd2.
**************************/
void pipeCommand(char** cmd1, char** cmd2) {
  int fds[2]; // file descriptors
  pipe(fds);
  // child process #1
  if (fork() == 0) {
    // Reassign stdin to fds[0] end of pipe.
    dup2(fds[0], STDIN_FILENO);
    close(fds[1]);
    close(fds[0]);
    // Execute the second command.
    // child process #2
    if (fork() == 0) {
        // Reassign stdout to fds[1] end of pipe.
        dup2(fds[1], STDOUT_FILENO);
        close(fds[0]);
        close(fds[1]);
        // Execute the first command.
        execvp(cmd1[0], cmd1);
    }
    wait(NULL);
    execvp(cmd2[0], cmd2);
    }
    close(fds[1]);
    close(fds[0]);
    wait(NULL);
}
Run Code Online (Sandbox Code Playgroud)


Bil*_*win 5

这是一个关于UNIX管道的教程,特别是关于如何在类似shell的架构中构建piplines:

http://www.cse.ohio-state.edu/~mamrak/CIS762/pipes_lab_notes.html

没有太多完整编写的代码,但它很好地描述了这些概念.

您还可以下载几乎所有shell的源代码,例如bash,tcsh,zsh等.