UNIX管道 - 从标准输入在孩子的描述符中读取数据 [英] Unix pipe - reading data from stdin in the child descriptor

查看:168
本文介绍了UNIX管道 - 从标准输入在孩子的描述符中读取数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现在C UNIX管道(即执行ls | WC)。我已经找到了相关的解决我的问题(çUNIX管道为例)不过,我不是知道为什么解决code段的特定部分的工作。

I'm trying to implement unix piping in c (i.e. execute ls | wc). I have found a related solution to my problem (C Unix Pipes Example) however, I am not sure why a specific portion of the solved code snippet works.

这里的code:

/* Run WC. */
int filedes[2];
pipe(filedes);

/* Run LS. */
pid_t pid = fork();
if (pid == 0) {
    /* Set stdout to the input side of the pipe, and run 'ls'. */
    dup2(filedes[1], 1);
    char *argv[] = {"ls", NULL};
    execv("/bin/ls", argv);
 } else {
    /* Close the input side of the pipe, to prevent it staying open. */
     close(filedes[1]);
 }

 /* Run WC. */
 pid = fork();
 if (pid == 0) {
      dup2(filedes[0], 0);
      char *argv[] = {"wc", NULL};
      execv("/usr/bin/wc", argv);
  }

在子进程执行wc命令,虽然它stndin重视文件描述符,我们似乎没有明确读出由第一子进程LS产生的输出。因此,对我来说似乎LS是独立运行的,当我们没有执行厕所时明确使用LS的输出厕所是独立运行的。那么如何做到这一点code工作(即它执行LS | WC)?

In the child process that executes the wc command, though it attaches stndin to a file descriptor, it seems that we are not explicitly reading the output produced by ls in the first child process. Thus, to me it seems that ls is run independently and wc is running independently as we not explicitly using the output of ls when executing wc. How then does this code work (i.e. it executes ls | wc)?

推荐答案

只是作品(它减少了一些弯道,但它的作品),因为分叉儿确保文件描述符的显示的code执行过程中会写(在 LS的情况下)和(在的WC 的情况下),读的是管道的适当端。你不必做任何更多;标准输入是文件描述符0,因此厕所无(文件名)参数从标准输入读取。 LS 总是写到标准输出,文件描述符1,除非是写一个错误信息。

The code shown just about works (it cuts a number of corners, but it works) because the forked children ensure that the the file descriptor that the executed process will write to (in the case of ls) and read from (in the case of wc) is the appropriate end of the pipe. You don't have to do any more; standard input is file descriptor 0, so wc with no (filename) arguments reads from standard input. ls always writes to standard output, file descriptor 1, unless it is writing an error message.

有在code段三个过程;父进程和两个孩子,分别来自叉()
父进程应该关闭两个的管道太两端;它仅关闭之一。

There are three processes in the code snippet; the parent process and two children, one from each fork(). The parent process should be closing both its ends of the pipe too; it only closes one.

在一般情况下,以后你做了 DUP() dup2()上一个管道文件描述符电话,应关闭的管的两端。你逃掉了这里,因为 LS 生成的数据和终止;你不会在所有情况下。

In general, after you do a dup() or dup2() call on a pipe file descriptor, you should close both ends of the pipe. You get away with it here because ls generates data and terminates; you wouldn't in all circumstances.

注释:

/* Set stdout to the input side of the pipe, and run 'ls'. */

是不正确的;你设置标准输出来管的输出端,而不是输入端。

is inaccurate; you're setting stdout to the output side of the pipe, not the input side.

您应该有 execv后一个错误的exit()通话;如果他们失败了,他们回来,这个过程可以造成严重破坏(例如,如果 LS 失败,你结束了的WC <两个副本/ code>运行。

You should have an error exit after the execv() calls; if they fail, they return, and the process can wreak havoc (for example, if the ls fails, you end up with two copies of wc running.

请注意所述管的两端,在每个过程的小心关闭。父进程有没有用,为管道一旦推出两个孩子。我离开了code而关闭与filedes [1] 在年初举行(但删除了一个明确的其他因为下面的code座也只有执行,如果其他被执行死刑)。我很可能在每个文件的地方需要关闭三个code路径保持的关闭对()

Note the careful closing of both ends of the pipe in each of the processes. The parent process has no use for the pipe once it has launched both children. I left the code which closes filedes[1] early in place (but removed it from an explicit else block since the following code was also only executed if the else was executed). I might well have kept pairs of closes() in each of the three code paths where files need to be closed.

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

int main(void)
{
    int filedes[2];
    int corpse;
    int status;
    pipe(filedes);

    /* Run LS. */
    pid_t pid = fork();
    if (pid == 0)
    {
        /* Set stdout to the output side of the pipe, and run 'ls'. */
        dup2(filedes[1], 1);
        close(filedes[1]);
        close(filedes[0]);
        char *argv[] = {"ls", NULL};
        execv("/bin/ls", argv);
        fprintf(stderr, "Failed to execute /bin/ls\n");
        exit(1);
    }
    /* Close the input side of the pipe, to prevent it staying open. */
    close(filedes[1]);

    /* Run WC. */
    pid = fork();
    if (pid == 0)
    {
        /* Set stdin to the input side of the pipe, and run 'wc'. */
        dup2(filedes[0], 0);
        close(filedes[0]);
        char *argv[] = {"wc", NULL};
        execv("/usr/bin/wc", argv);
        fprintf(stderr, "Failed to execute /usr/bin/wc\n");
        exit(1);
    }

    close(filedes[0]);

    while ((corpse = waitpid(-1, &status, 0)) > 0)
        printf("PID %d died 0x%.4X\n", corpse, status);
    return(0);

}

输出示例:

$ ./pipes-14312939
      32      32     389
PID 75954 died 0x0000
PID 75955 died 0x0000
$

这篇关于UNIX管道 - 从标准输入在孩子的描述符中读取数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆