管道和流程管理

时间:2014-11-11 21:18:45

标签: c shell pipe waitpid

我正在开发一个用C实现的小shell(tsh)(这是一个赋值)。任务的一部分属于PIPING。我必须将命令的输出传递给另一个命令。例如:ls -l | sort

当我运行shell时,我在其上执行的每个命令都由它生成的子进程处理。孩子完成后,返回结果。对于管道我想首先实现一个编码的例子来检查它是如何工作的。我写了一个部分有效的方法。问题是当我运行管道命令时,在子进程完成后,整个程序退出它!显然我没有正确处理子进程信号(下面的方法代码)。

我的问题:

  • 如何使用pipe()进行流程管理?如果我运行一个命令ls -l | sort它是否为ls -l创建了一个子进程,为sort创建了另一个进程?从我到目前为止看到的管道示例中,只创建了一个进程(fork())。

  • 当处理第二个命令(我们示例中为sort)时,如何获取其进程ID?

编辑:同时运行此代码时,我得到两次结果。不知道它为什么会跑两次,那里没有循环。

这是我的代码:

pid_t pipeIt(void){
    pid_t pid;
    int pipefd[2];

    if(pipe(pipefd)){
        unix_error("pipe");
        return -1;
    }

    if((pid = fork()) <0){
        unix_error("fork");
        return -1;  
    }
    if(pid == 0){
        close(pipefd[0]);
        dup2(pipefd[1],1);
        close(pipefd[1]);
        if(execl("/bin/ls", "ls", (char *)NULL) < 0){
            unix_error("/bin/ls");
            return -1;
        }// End of if command wasn't successful

    }// End of pid == 0
    else{
        close(pipefd[1]);
        dup2(pipefd[0],0);
        close(pipefd[0]);
        if(execl("/usr/bin/tr", "tr", "e", "f", (char *)NULL) < 0){
            unix_error("/usr/bin/tr");
            return -1;
        }
    }

    return pid;

}// End of pipeIt

2 个答案:

答案 0 :(得分:1)

是的,shell必须fork来执行每个子进程。请记住,当您调用其中一个execve()函数系列时,将替换当前过程映像与exec的一个。如果shell直接执行子进程,则shell无法继续处理其他命令,因为此后它不再存在(除了子进程外)。

要修复它,只需在fork()分支中再次pid == 0,并在该子代中执行ls命令。如果您不是要异步执行管道,请记住wait()两个(所有)子进程。

答案 1 :(得分:0)

是的,您需要至少调用两次fork,一次为管道中的每个程序调用一次。请记住,exec会替换当前进程的程序映像,因此shell会在您开始运行sort或(tr)时停止存在。