重定向标准流

Redirecting standard stream

我正在尝试在 shell 中创建管道以重定向标准流,但我现在卡住了。

当我尝试 运行 此代码时:

int fd[2];
pid_t pid;

pipe(fd);

pid = fork();
if (pid == 0)
{
  // child process

  // redirect standard input and output
  dup2(fd[1], STDOUT_FILENO);
  dup2(fd[0], STDIN_FILENO);

  // close them (they are now redirected)
  close(fd[0]);
  close(fd[1]);

  char *input_argv[] = {"/bin/ls", "/bin/ls", ">", "out.txt", NULL};

  execv(input_argv[0], input_argv);
}
else if (pid > 0)
{
  // parent process

  waitpid(pid, NULL,0);
}

我收到以下错误消息:

/bin/ls: cannot access >: No such file or directory
/bin/ls: cannot access out.txt: No such file or directory

我不知道它们是什么意思,是什么原因造成的,也不知道如何解决。

我做错了什么?

总而言之,代码没有任何意义。我认为这里可以给出的最佳答案是解释最有问题的部分:

  // redirect standard input and output
  dup2(fd[1], STDOUT_FILENO);
  dup2(fd[0], STDIN_FILENO);

fd[0]是读端,fd[1]是一个管道的写端。您写入 fd[1] 的任何内容都可以在 fd[0] 上读取。所以,这只是 "short-circuiting" 你的 stdio 流,一点用处都没有。

通常你想用管道做的是在 parent 和 child 进程之间每个通信方向有一个管道(例如 child 应该从 parent 读取: dup2()读端到STDIN_FILENO在child写到写端从parent).

  char *input_argv[] = {"/bin/ls", "/bin/ls", ">", "out.txt", NULL};

现在这也说不通了。 > 告诉 shell 打开文件进行写入,exec() child 已经重定向 STDOUT_FILENO到位。这肯定 不是 此处 ls 理解的论点。你没有shell,直接exec()ls就可以了

如果您的初衷是模仿 shell 在给定条件下会做什么

ls > out.txt

您应该只打开文件 out.txt 进行写入,并在 child 代码中 dup2() 您打开的文件的文件描述符 STDOUT_FILENO 在 [=21= 之前]ing ls。在这种场景中不需要管道。


编辑 如果您想了解 shell 在内部为 ls > out.txt 做了什么:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
    /* open file for writing */
    int outfd = open("/tmp/out.txt", O_CREAT|O_WRONLY, 00666);
    if (outfd < 0)
    {
        perror("open()");
        return EXIT_FAILURE;
    }

    /* fork child */
    int pid = fork();
    if (pid < 0)
    {
        perror("fork()");
        return EXIT_FAILURE;
    }

    if (pid == 0)
    {
        /* in the child, redirect stdout to our file */
        if (dup2(outfd, STDOUT_FILENO) < 0)
        {
            perror("dup2()");
            return EXIT_FAILURE;
        }
        close(outfd);

        /* then execute 'ls' */
        execlp("ls", "ls", 0);

        /* only reached when execlp() fails: */
        perror("execlp()");
        return EXIT_FAILURE;
    }

    /* we don't need the output file in the parent process: */
    close(outfd);

    /* wait for child to complete */
    int childrc;
    waitpid(pid, &childrc, 0);

    /* return exit code of child process */
    return childrc;
}

当然,实际 shell 的代码看起来不同(没有硬编码名称,使用 execv* 系列函数,因为它事先不知道参数的数量,等等。)