如何实现Bash才能执行“cat | ls”命令?

问题描述 投票:0回答:1

我一直在尝试用 C 语言开发一个迷你 shell 程序,其行为主要类似于 Bash。但是,我在执行此命令时遇到问题:

cat | ls
。在我的程序中,当我执行此命令时,它会等待来自
stdin
的输入,并且仅当
ls
到达
cat
时才打印
EOF
命令的输出,这仅在我发送
ctrl+D
时发生。向程序发出信号。另一方面,在 Bash 中,当我执行
cat | ls
命令时,它首先将
ls
命令的输出打印到
stdout
并等待来自
stdin
的输入,并在输入一个后停止执行整个命令
stdin
.

的输入行

我创建了一个最小的、可重现的程序示例,它的工作方式相同。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void execute_block(char **block)
{
    int pid;

    pid = fork();
    if (pid == -1)
        exit(EXIT_FAILURE);
    if (pid == 0)
    {
        if (execve(block[0], block, NULL) == -1)
        {
            perror(block[0]);
            exit(127);
        }
        exit(EXIT_SUCCESS);
    }
    waitpid(pid, NULL, 0);
}

void handle_commands(char **block1, char **block2)
{
    int pid;
    int pipefd[2];

    if (pipe(pipefd) == -1)
        exit(EXIT_FAILURE);
    pid = fork();
    if (pid == -1)
        exit(EXIT_FAILURE);
    if (pid == 0)
    {
        close(pipefd[0]);
        dup2(pipefd[1], STDOUT_FILENO);
        close(pipefd[1]);
        execute_block(block1);
        exit(EXIT_SUCCESS);
    }
    close(pipefd[1]);
    dup2(pipefd[0], STDIN_FILENO);
    close(pipefd[0]);
    waitpid(pid, NULL, 0);
    execute_block(block2);
}

int main(int argc, char **argv, char **envp)
{
    char *block1[] = {"/bin/cat", NULL};
    char *block2[] = {"/bin/ls", NULL};

    handle_commands(block1, block2);
}

为什么我的程序的行为方式与 Bash 不同。这和我处理管道的方式有关吗?或者是别的什么?另外,这个问题是否是由于我使用 waitpid() 函数的方式导致的?

c linux shell
1个回答
0
投票

你的

handle commands
代码基本上是

  1. 分叉一个孩子
  2. 在孩子身上
    • 运行 block1 命令
    • 退出
  3. 在父级中
    • 等待孩子退出
    • 运行block2命令
    • 退出

因此,这意味着

ls
(block2 命令)在子级(block1 命令中的
cat
)退出之前根本不会运行。

普通的 shell(如 bash)将分叉一个 second 子级并使用它来运行 block2 before waiting - 父级将在两个子级都启动后等待(对于两个子级),因此它们将同时运行

© www.soinside.com 2019 - 2024. All rights reserved.