我正在研究用 C 语言实现的微型 shell(tsh)(这是一项作业)。作业的一部分属于 PIPING。我必须将一个命令的输出通过管道传递给另一个命令。例如:ls -l |排序
当我运行 shell 时,我在其上执行的每个命令都由它生成的子进程处理。 child 完成后返回结果。对于管道,我想先实现一个硬编码示例来检查它是如何工作的。我写了一个方法,部分有效。问题是当我运行管道命令时,子进程完成后,整个程序随之退出!显然我没有正确处理子进程信号(下面的方法代码)。
我的问题:
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
最佳答案
是的,shell 必须 fork 来执行每个子进程。请记住,当您调用 execve()
函数族之一时,它会用已执行的进程镜像替换当前进程镜像。如果它直接执行子进程,您的 shell 将无法继续处理更多命令,因为此后它不再存在(子进程除外)。
要修复它,只需在 pid == 0
分支中再次使用 fork()
,然后在该子分支中执行 ls
命令。如果您不想异步执行管道,请记住为两个(所有)子进程使用 wait()
。
关于c - 管道和过程管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48350893/