c - dup2 是在 linux 终端中模拟命令序列行为的正确方法吗?

标签 c pipe stdout stdin dup2

我正在尝试模拟 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,但我想确定我应该怎么做才能修复它

最佳答案

你做对了几件事:

  1. 您正在创建一个新流程并正确检查状态。
  2. 您有权关闭管道的所有子进程和父进程不需要的文件句柄。

您需要做对的事情:

当 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 信号,因为管道仍处于打开状态(由父级)。

关于c - dup2 是在 linux 终端中模拟命令序列行为的正确方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55440889/

相关文章:

c - 如何调试这个基本的 OR 程序?

c - 如何使用一个程序的返回值作为另一个程序的输入?

debugging - 在 Fortran 中查找 write 语句

C fgets 会跳过用户输入,即使在刷新缓冲区时也是如此

c++ - 为什么 GetLastError() (NOT GetReturnMessage) 在用户名错误时返回 “wrong password”?

c - 避免在 C 程序中使用 main(入口点)

python-2.7 - 将一个 docker 容器的 stdout 附加到另一个 docker 容器的 stdin

Linux 管道行为

c - 为什么要在 Linux 中关闭管道?

python - 将多个参数传递给 sys.stdout.write