在C中重新创建管道执行问题

64jmpszr  于 2023-03-01  发布在  其他
关注(0)|答案(1)|浏览(137)

我实际上正在做一个项目,我们正在尝试用C语言重新创建一个bash终端。我在代码中处理管道时遇到了一些问题。正如你在写“cat”时所知道的|ls”,它首先显示ls结果,然后打开标准输入,但只打开一行。问题是我处理管道的方式,首先它显示ls结果为异常,但在标准输入阅读之后,直到我按下CTRL-D。我想让它在第一行之后结束,就像bash一样。我想我的水管有问题,但我试着用其他方法改造,结果总是一样的问题。
我的代码:

void    make_command(t_list *cmds, char **env)
{
    char    *path;
    int     exec;
    
    path = get_path((char *)cmds->content[0], env);
    if (!path)
        return ;
    exec = execve(path, (char **)cmds->content, env);
    if (exec < 0)
        exit_error();
}

void    make_pipe(t_list *cmds, char **env, t_listpids **pids, int *fd_old)
{
    pid_t       pid;
    int         tube[2];

    while (cmds)
    {
        if (pipe(tube) == -1)
            exit_error();
        pid = fork();
        if (pid == 0)
        {
            if (cmds->previous) //only if not first command
            {
                dup2((*fd_old), STDIN_FILENO);
                close(*fd_old);
            }
            if (cmds->next) //only if not last command
            {
                dup2(tube[1], STDOUT_FILENO);
                close(tube[1]);
            }
            make_command(cmds, env); //execute command function with execve
            close(tube[0]);
            close(tube[1]);
            exit(EXIT_SUCCESS);
        }
        else
        {
            add_pids(pid, pids); //add pid to chained list of pids (used to waitpid them after)
            *fd_old = tube[0];
            close(tube[1]);
            cmds = cmds->next;
            while (cmds && ft_strncmp((char *)cmds->content[0], "|", 1) == 0)
                cmds = cmds->next;
        }
    }
}
yzuktlbb

yzuktlbb1#

当你写“猫”的时候|ls”时,首先显示ls结果,然后打开标准输入,但仅显示一行。
这是一个令人困惑的描述,在很大程度上是荒谬的管道发生了什么。这里有一个更好的:ls运行到完成,不等待任何输入,同时cat等待其标准输入上的输入,并在阅读一行后终止,不将该行回显到终端。
两者之间的重要区别:

  • 在强制cat等待它的意义上,ls命令并不首先运行。它本身简单地不必等待任何用户输入,因此其输出被立即显示。
  • 没有新的标准输入被“打开”。cat命令从 shell 继承其标准输入,并且从该文件读取直到其终止。由于处于前台,它代替 shell 接收输入。

此外,cat在阅读一行后终止是偶然的。如果有更多的行排队等待它立即读取,或者可能由于某种原因ls运行缓慢,它可能会读取更多的行。当它终止时,这是因为它试图写入没有读取器的管道。这会导致SIGPIPE被传递给它,从而导致它终止。
这些都是相关的,因为它指出了您所描述的(错误)行为的问题。在您的例子中,cat一直阅读输入,直到您键入Ctrl-D,这立即告诉我,要么它的标准输出根本没有连接到管道,要么它所连接的管道仍然在某个地方打开以供读取。
知道了要查找什么,我们就可以确信,是的,父进程无法关闭它创建的管道的“每一个”的读端,它将它们保存在*fd_old中,一次一个,以便能够重定向下一个子进程的标准输入,但是在提供了重定向之后,它泄漏了打开文件描述符的副本。
它只需要在下一个fork()之前保持FD打开,所以也许您需要在else块中关闭它,如下所示:

else
        {
            if (cmds->previous) //only if not first command
            {
                close(*fd_old);
            }
            add_pids(pid, pids); //add pid to chained list of pids (used to waitpid them after)
            *fd_old = tube[0];
            close(tube[1]);
            cmds = cmds->next;
            while (cmds && ft_strncmp((char *)cmds->content[0], "|", 1) == 0)
                cmds = cmds->next;
        }

在循环结束后,你可能还需要关闭最后一个变量,我通常是这么认为的,但是你是通过指针间接存储它的,这让我不确定你到底想做什么。

相关问题