[英]Pipe function in Linux shell write in C
我的迷你外壳程序接受管道命令,例如ls -l | wc -l
ls -l | wc -l
并使用 excevp 来执行这些命令。
我的问题是,如果 execvp 没有 fork(),管道命令运行良好,但 shell 之后终止。 如果execvp 有fork(),就会发生死循环。 我无法修复它。
代码:
void run_pipe(char **args){
int ps[2];
pipe(ps);
pid_t pid = fork();
pid_t child_pid;
int child_status;
if(pid == 0){ // child process
close(1);
close(ps[0]);
dup2(ps[1], 1);
//e.g. cmd[0] = "ls", cmd[1] = "-l"
char ** cmd = split(args[index], " \t");
//if fork here, program cannot continue with infinite loop somewhere
if(fork()==0){
if (execvp(cmd[0],cmd)==-1){
printf("%s: Command not found.\n", args[0]);
}
}
wait(0);
}
else{ // parent process
close(0);
close(ps[1]);
dup2(ps[0],0);
//e.g. cmd[0] = "wc", cmd[1] = "-l"
char ** cmd = split(args[index+1], " \t");
//if fork here, program cannot continue with infinite loop somewhere
if(fork()==0){
if (execvp(cmd[0],cmd)==-1){
printf("%s: Command not found.\n", args[0]);
}
}
wait(0);
waitpid(pid, &child_status, 0);
}
}
我知道 excevp 需要 fork() 才能不终止 shell 程序,但我仍然无法修复它。 任何帮助将不胜感激,谢谢!
我应该如何让两个孩子平行?
pid = fork();
if( pid == 0){
// child
} else{ // parent
pid1 = fork();
if(pid1 == 0){
// second child
} else // parent
}
这样对吗?
是的, execvp()
用不同的程序替换了调用它的程序。 如果您想生成另一个程序而不结束执行生成的程序(即 shell),那么该程序必须fork()
创建一个新进程,并让新进程执行execvp()
。
您的程序源表现出错误的并行性,这可能会让您感到困惑或反映出更深层次的困惑。 您以与 fork 之后父进程的行为相同的方式构建第一个子进程的行为,但应该并行的是第一个子进程的行为和第二个子进程的行为。
一种结果是你的程序有太多的分叉。 初始进程应该分叉两次——每个它想要生成的子进程一次——并且两个子进程都不应该分叉,因为它已经是一个专用于您要运行的命令之一的进程。 但是,在您的实际程序中,第一个孩子确实分叉了。 这种情况可能是由孩子也为孙子wait()
拯救的,但它的形式凌乱且糟糕。
另一个结果是,当您设置第二个孩子的文件描述符时,您在分叉之前操作父级的,而不是在分叉后操作子级的。 这些更改将保留在父进程中,我非常有信心这不是您想要的。 这可能是 shell 似乎挂起的原因:当run_pipe()
返回时(shell 的标准输入已更改为管道的读取端)。
此外,父进程应该关闭管道两端的孩子都被分叉后,或多或少,孩子们必须在每个接近结束时,他们使用的不是一样的道理。 最后,管道的每一端都会有一个文件描述符的打开副本,一个在一个子节点中,另一个在另一个子节点中。 在某些情况下,未能正确执行此操作也可能导致挂起,因为您 fork 的进程可能不会终止。
以下是您希望程序执行的操作的摘要:
execvp()
使用execvp()
(或该系列中的其他函数之一)来运行请求的程序wait()
或waitpid()
来收集两个孩子。还要注意,您应该检查所有函数调用的返回值,并为错误提供适当的处理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.