重定向标准流

时间:2015-10-16 17:18:20

标签: c linux pipe exec fork

我试图在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

我不知道它们是什么意思,是什么导致它们以及如何解决它们。

我做错了什么?

1 个答案:

答案 0 :(得分:2)

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

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

fd[0]是读取结束,fd[1]是管道的写入结束。您写给fd[1]的任何内容均可在fd[0]上阅读。所以,这只是“短路”你的stdio流,根本没用。

您想要对管道做什么通常在父进程和子进程之间的每个方向上都有一个管道(例如,孩子应该从父进程中读取:dup2()将阅读结束发送到子进程中的STDIN_FILENO和从父母写到写作结束。)

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

现在这也没有意义。 >告诉 shell 打开要写入的文件,并exec()已经重定向STDOUT_FILENO的孩子。这肯定是 ls所理解的论点。你没有shell,直接exec() ls

如果你的初衷是模仿shell在给定时会做什么

ls > out.txt

您应该在out.txt dup2()之前打开文件STDOUT_FILENO进行编写,并在子代码exec()中将打开文件的文件描述符打开到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*系列函数,因为它事先不知道参数的数量,依此类推。)< / p>