Linuxshell中的管道函数用C写
Pipe function in Linux shell write in C
我的 mini-shell 程序接受管道命令,例如 ls -l | wc -l
并使用 excevp 来执行这些命令。
我的问题是,如果没有用于 execvp 的 fork(),管道命令运行良好,但 shell 随后终止。如果有 fork() for execvp,就会发生死循环。而且我无法修复它。
代码:
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 程序,但我仍然无法修复它。任何帮助将不胜感激,谢谢!
如何让两个children平行?
pid = fork();
if( pid == 0){
// child
} else{ // parent
pid1 = fork();
if(pid1 == 0){
// second child
} else // parent
}
这是正确的吗?
是的,execvp()
用另一个程序替换了调用它的程序。如果你想生成另一个程序而不结束执行生成的程序(即 shell),那么该程序必须 fork()
来创建一个新进程,并让新进程执行 execvp()
.
您的程序源代码表现出错误的并行性,可能使您感到困惑或反映出更深层次的困惑。您构造第一个 child 分叉的行为的方式与分叉后 parent 进程的行为相同,但是 应该 并行的是第一个 child 的行为和第二个 child.
的行为
一个结果是您的程序有太多分支。初始进程应该恰好分叉两次——每个 child 它想要产生一次——并且 child 都不应该分叉,因为它已经是一个专用于你想要 [=74= 的命令之一的进程].然而,在您的实际程序中,第一个 child 确实会派生。 child 也可能 wait()
为 grandchild 挽救了那个箱子,但它很乱而且形式不佳。
另一个结果是,当您设置第二个 child 的文件描述符时,您在分叉之前操作了 parent,而不是操作 child'分叉之后。这些更改将持续存在于 parent 过程中,我很确定这不是您想要的。这可能就是 shell 似乎挂起的原因:当 run_pipe()
returns(shell 的标准输入已更改为管道的读取端)。
此外,parent 进程应该在 children 都被分叉后关闭管道的 both 端,或多或少相同children 必须各自关闭他们不使用的那一端的原因。最后,管道的每一端都会有一个文件描述符的打开副本,一个在一个 child 中,另一个在另一个中。如果未能正确执行此操作,在某些情况下也会导致挂起,因为您分叉的进程可能不会终止。
以下是您希望程序执行的操作的摘要:
- 原始进程设置管道。
- 原始进程 fork 两次,每个命令一次。
- 每个子进程都操纵自己的文件描述符,以使用管道的正确一端作为适当的标准 FD,并关闭管道的另一端。
- 每个子进程使用
execvp()
(或该系列中的其他函数之一)来 运行 请求的程序
- parent 关闭管道两端的文件描述符副本
- parent用
wait()
或waitpid()
收两个children.
另请注意,您应该检查所有函数调用的 return 值并提供适当的错误处理。
我的 mini-shell 程序接受管道命令,例如 ls -l | wc -l
并使用 excevp 来执行这些命令。
我的问题是,如果没有用于 execvp 的 fork(),管道命令运行良好,但 shell 随后终止。如果有 fork() for execvp,就会发生死循环。而且我无法修复它。
代码:
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 程序,但我仍然无法修复它。任何帮助将不胜感激,谢谢!
如何让两个children平行?
pid = fork();
if( pid == 0){
// child
} else{ // parent
pid1 = fork();
if(pid1 == 0){
// second child
} else // parent
}
这是正确的吗?
是的,execvp()
用另一个程序替换了调用它的程序。如果你想生成另一个程序而不结束执行生成的程序(即 shell),那么该程序必须 fork()
来创建一个新进程,并让新进程执行 execvp()
.
您的程序源代码表现出错误的并行性,可能使您感到困惑或反映出更深层次的困惑。您构造第一个 child 分叉的行为的方式与分叉后 parent 进程的行为相同,但是 应该 并行的是第一个 child 的行为和第二个 child.
的行为一个结果是您的程序有太多分支。初始进程应该恰好分叉两次——每个 child 它想要产生一次——并且 child 都不应该分叉,因为它已经是一个专用于你想要 [=74= 的命令之一的进程].然而,在您的实际程序中,第一个 child 确实会派生。 child 也可能 wait()
为 grandchild 挽救了那个箱子,但它很乱而且形式不佳。
另一个结果是,当您设置第二个 child 的文件描述符时,您在分叉之前操作了 parent,而不是操作 child'分叉之后。这些更改将持续存在于 parent 过程中,我很确定这不是您想要的。这可能就是 shell 似乎挂起的原因:当 run_pipe()
returns(shell 的标准输入已更改为管道的读取端)。
此外,parent 进程应该在 children 都被分叉后关闭管道的 both 端,或多或少相同children 必须各自关闭他们不使用的那一端的原因。最后,管道的每一端都会有一个文件描述符的打开副本,一个在一个 child 中,另一个在另一个中。如果未能正确执行此操作,在某些情况下也会导致挂起,因为您分叉的进程可能不会终止。
以下是您希望程序执行的操作的摘要:
- 原始进程设置管道。
- 原始进程 fork 两次,每个命令一次。
- 每个子进程都操纵自己的文件描述符,以使用管道的正确一端作为适当的标准 FD,并关闭管道的另一端。
- 每个子进程使用
execvp()
(或该系列中的其他函数之一)来 运行 请求的程序 - parent 关闭管道两端的文件描述符副本
- parent用
wait()
或waitpid()
收两个children.
另请注意,您应该检查所有函数调用的 return 值并提供适当的错误处理。