c - 在抽象语法树中递归执行管道

标签 c shell pipe fork abstract-syntax-tree

我已经成功地为我的 minishell 制作了一个抽象语法树,事情是 当我尝试执行管道命令时,我被卡住了。

第一个管道执行并将结果输出到 stdout 1,而第二个 grep filename 要么卡住要么根本不执行。

我尝试了不同的方法,得到了不同的结果,但没有一个主题有效

如果有任何帮助,我将不胜感激。

这就是我的 AST 的样子。

ls -la | cat -e | grep filename

enter image description here

t_node      *pipe_execution(t_node *node, t_list *blt, t_line *line, int std[2])
{
    int pp[2];

    if (node)
    {
        if (node->kind == NODE_PIPE)
        {
            if (node->and_or_command->left)
            {
                pipe(pp);
                std[1] = pp[1];
                pipe_execution(node->and_or_command->left, blt, line, std);
                close(pp[1]);
            }
            if (node->and_or_command->right)
            {
                std[0] = pp[0];
                std[1] = 1;
                dprintf(2, "right std %d\n", std[1]);
                pipe_execution(node->and_or_command->right, blt, line, std);
                close(std[0]);
            }
        } else if (node->kind == NODE_SIMPLE_COMMAND)
        {
            dprintf(2, "====%s=== and stdin %d stdout %d\n", node->simple_command->head->name, std[0], std[1]);
            execute_shell(blt, line->env, node, std);
        }
    }
    return (node);
}
int        execute_shell(t_list *blt, t_list *env, t_node *node, int std[2])
{
    ...
    return (my_fork(path, env, cmds, std));
}

我的 fork 进程的实现。

int         my_fork(char *path, t_list *env, char **cmds, int std[2])
{
    pid_t       child;
    char        **env_tab;
    int         status;

    status = 0;
    env_tab = env_to_tab(env);
    child = fork();
    if (child > 0)
        waitpid(child, &status, 0);
    else if (child == 0)
    {
        dup2(std[0], 0);
        dup2(std[1], 1);
        execve(path, cmds, env_tab);
    }
    return (status);
}

我希望这段代码有意义。

最佳答案

管道需要并发执行

据我从您提供的代码片段中可以看出,问题在于 my_fork()正在阻塞。因此,当您执行一个进程时,您的 shell 会停止并等待该进程完成,然后再开始下一个进程。如果你做一些简单的事情,比如:

/bin/echo Hello | cat

那么管道的内部缓冲区足够大,可以存储整个输入字符串 Hello 。一旦/bin/echo进程完成后,您执行cat ,然后可以从管道读取缓冲的数据。然而,一旦事情变得更加复杂,或者当第一个进程向管道发送更多数据时,其内部缓冲区就会满,然后就会阻塞。

解决方案是推迟调用waitpid()在您派生的进程上,直到生成属于命令行一部分的所有进程。

在启动进程之前创建所有必需的管道

您的函数pipe_execution()假设只有一个管道;它使用 filedescriptor 0 启动第一个进程。作为其输入,它使用 filedescriptor 1 启动第二个进程。作为其输出。但是,如果单个命令行上有多个管道,例如 ls -la | cat -e | grep filename ,然后输出 cat -e进程需要进入第二个管道,而不是标准输出。

您需要在启动第一个管道的右侧命令之前创建第二个管道。在启动任何命令之前创建所有管道可能是最简单的。您可以通过定义多个阶段来做到这一点:

  1. 创建管道
  2. 启动命令
  3. 等待所有命令完成

您可以多次遍历您构建的抽象语法树,每次执行其中一个阶段。

关于c - 在抽象语法树中递归执行管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59602615/

相关文章:

C 在 for 循环中没有 printf

c - 扫描整数数组

arrays - 检查元素是否存在于 Bash 数组中

python - 使用管道将数据从 c 程序发送到 python 程序?

linux - Linux 新手

c - 指向从代码复制的函数的指针

java - C/C++函数/方法与Java的比较

bash - 在 shell 脚本中解压缩文件时出错。 - 需要PK兼容。 v5.1(可以做v4.6)

postgresql - 在变量上使用 shell 脚本存储 PostgreSQL 查询

c - 通过管道从多个子进程写入父进程