带有内置命令(如echo)的管道损坏

6yjfywim  于 2023-02-11  发布在  其他
关注(0)|答案(1)|浏览(166)

我的程序有些问题。
我有一个学校作业,我必须重现bash的一些特性作业几乎完成了,但我有一个问题,与内置的命令和管道确实我有一个坏管道错误,每当内置的命令是最后一个管道这样:ls|echo(此行将产生管道破裂错误),其中echo|ls将工作得很好。经过一些研究,我发现了什么问题,我有这个错误,因为为内置命令(意味着我不使用execve来调用它们)当其他命令被分叉时,我不将它们分叉到子进程中,所以我猜测是,当ls还在写入管道时,build_command关闭管道read_end的速度太快了。我处理这个错误的方法是为内置命令派生一个进程。但是我想知道它们是否是一个不派生内置命令的解决方案,因为这会使用不必要的资源。

void    execute_routine(t_data *data, t_cmd *cmd)
{
    pid_t   pid_ret;

    if (data -> s_pipes && !ft_strcmp(cmd -> prev_stop, "|")
        && cmd -> prev_cmd -> p_close)
        close_fd(data, "bash", &data -> s_pipes -> s_pipes[1]);
    if (!built_in(data, cmd, 0))
    {
        pid_ret = fork();
        if (pid_ret < 0)
            print_err_and_exit(data, NULL, "bash", 1);
        if (pid_ret == 0)
            forking(cmd);
        cmd -> pid = pid_ret;
    }
    handle_pipes(data, cmd);
}

在上面,是通过readline的帮助执行每个命令get的函数,你可以看到,如果命令是内置的,我们不会派生它,它将被直接处理到该函数中,对于echo的情况,下面是该函数:

int echo(t_data *data, t_cmd *cmd)
{
    int fd;

    data -> status = 1;
    if (open_check_files_built_in(cmd, cmd -> tab))
        return (1);
    fd = where_to_write(data, cmd);
    if (ft_tab_len(cmd -> args) == 1)
    {
        if (write_to_fd(data, "\n", fd) < 0)
            return (print_err_built_in("bash", 1));
        data -> status = 0;
        return (1);
    }
    if (write_args_(data, cmd, fd))
        return (1);
    if (cmd -> last_in && cmd -> last_in -> type == IN)
        close_fd_built_in(&cmd -> last_in -> fd);
    if (cmd -> last_out)
        close_fd_built_in(&cmd -> last_out -> fd);
    data -> status = 0;
    return (1);
}

对于echo,我只寻找输出重定向和写入返回的fd。当我完成函数时,我在该函数中使用管道。

void    handle_pipes(t_data *data, t_cmd *cmd)
{
    if (data -> s_pipes && data -> prev_pipes == -1
        && !ft_strcmp(cmd -> prev_stop, "|"))
        close_fd(data, "bash", &data -> s_pipes -> read_end -> s_pipes[0]);
    close_fd(data, "bash error", &data -> prev_pipes);
    if (data -> inited)
    {
        data -> prev_pipes = data -> pipes[0];
        close_fd(data, "bash pipes close", &data -> pipes[1]);
    }
    data -> inited = 0;
}

之后,我等待我的所有进程与下面的函数

int i;

   i = -1;
   while (cmds[++i])
   {
        if (cmds[i]-> pid && waitpid(
                cmds[i]-> pid, &data -> status, 0) < 0 && errno != ECHILD)
            print_err_and_exit(data, NULL, "Error with waitpid", 1);
    }

正如我前面所说的,built_in命令和其他命令之间的唯一区别是,built_in命令不是在父进程中派生和直接处理的,而其他命令是在子进程中派生和处理的。尽管我有管道破裂错误信号,但管道仍然输出预期的结果,例如ls|echo bonjour仍然会将bonjour输出到STDOUT,但处理ls命令的进程会将错误SIGPIPE发送到waitpid,而echo bonjour|ls也将工作良好,并返回状态代码0而不是13。

bxjv4tth

bxjv4tth1#

问题是您误解了“echo”的性质与“ls"的性质,以及“pipes”的性质
ls”可能是多行函数。它生成流。
管道”是一种在一个进程创建流 * 和另一个进程使用该流作为输入 * 之间创建进程间通信的机制。
以下是你未能理解“echo"本质的地方:echo不是一个面向多行(也叫流)的工具!它是一个单行工具,适合于一个“单”参数字符串。该字符串可以是多行的,但它被传递给echo,echo只将其解释为一个单参数,而不关心其内容是什么。
甚至手册页**也没有提到echo接受来自stdin的输入!*换句话说, 它甚至没有打开管道流 *。
希望这能澄清你所认为的关于“s”的谜团|echo”管道。

相关问题