我正在尝试模拟 linux 中终端的行为,用 C 代码构建一个 minishell,但我在尝试实现命令序列时遇到了一个问题,因为第一个命令的输出不会被正确接收由下一个通过管道。我们想要实现的方法是通过管道将第一个命令( child 1)的标准输出传递给第二个命令( child 2,在 child 1 死后出生),并将其用作第二个命令的标准输入。请注意,我在 for 循环的开头使用了 fork() 语句,因此每次迭代都会创建一个在另一个 child 出生之前死亡的 child 。
我试过使用除 dup2 之外的其他命令,但没有任何效果。此外,当使用“ls | sort”等命令示例并拦截第一个命令的输出时,第一个命令似乎返回已排序的列表。
argvv 是一个 char *** 类型的变量,在第一级中每个命令包含一个条目,在第二级中每个命令包含一个带有每个参数的条目
/*pipes have been created already; p1, p2 (p2 only useful for sequences of 3 commands)*/
for (command_counter = 0; command_counter < num_commands; command_counter++)
{
int chid = fork();
switch (chid)
{
case 0: // child
//COMMAND EXECUTION
/*Running commands with pipes */
/*Data is only ran through pipes if there's more than one command*/
/*we only implemented the version for two commands so far*/
/*...*/
if(num_commands==2)
{
/*Data is only ran through pipes if there's more than one command*/
if(command_counter==0)
{//The first command takes no input from pipe
close(p1[0]);
close(p2[0]);
close(p2[1]);
dup2(p1[1], 1);
close(p1[1]);
}
if(command_counter==1)
{ //Last command takes input only, output goes to stdout or output file
close(p2[1]);
close(p2[0]);
close(p1[1]);
dup2(p1[0], 0);
close(p1[0]);
}
}
execvp(argvv[command_counter][0], argvv[command_counter]);
case -1: // error
perror("Couldn't create child process\n");
exit(-1);
default:
// father
waitpid(chid, 0, 0);
}
}
close(p1[1]);
close(p1[0]);
close(p2[1]);
close(p2[0]);
我希望程序能正常运行,但它只是在执行排序命令时停止了。我很确定错误是在第二次迭代中使用 dup2,但我想确定我应该怎么做才能修复它
请您参考如下方法:
你做对了几件事:
- 您正在创建一个新流程并正确检查状态。
- 您有权关闭管道的所有子进程和父进程不需要的文件句柄。
您需要做对的事情:
当 child[command_counter] 创建时,它共享 child[command_counter-1
的管道] (如果 command_counter >= 0
),以及 child[command_counter +1]
的管道(如果 command_counter +1 < num_commands
)。
您应该仅在创建最后一个 child 后才开始等待 child 。如果您提前开始等待,那么其中一个管道可能会被填满,系统将开始等待进程读取该管道。但是如果最后一个 child 还没有创建,那么就没有人在读管道,整个事情就陷入了僵局。 (当作者等待它被读取时,没有人正在读取管道)。
如果您在开始等待之前预先创建了所有进程,那么不要忘记在开始等待之前关闭父进程中的所有管道。否则,当第一个 child 完成时,后面的 child 将不会收到 EOF 信号,因为管道仍处于打开状态(由父级)。