简体   繁体   English

使用dup2使C程序执行诸如'ls / bin | grep | grep | grep b'

[英]Trouble using dup2 to make a C program execute a command such as 'ls /bin | grep grep | grep b'

I'm having trouble using dup2 to make ac program execute a command such as ls /bin | grep grep | grep b 我在使用dup2使ac程序执行ls /bin | grep grep | grep b等命令时遇到问题 ls /bin | grep grep | grep b ls /bin | grep grep | grep b . ls /bin | grep grep | grep b When I comment out the third command and associated pipe it executes ls /bin | grep grep 当我注释掉第三个命令和相关管道时,它执行ls /bin | grep grep ls /bin | grep grep fine, but with the last command it just returns right away. ls /bin | grep grep很好,但是使用最后一个命令,它会立即返回。 Also when I enter 'ps' the processes are still running. 同样,当我输入“ ps”时,进程仍在运行。 I think it's due to how I close the pipes. 我认为这是由于我如何关闭管道。 My code is below: 我的代码如下:

int main()
{
    int pipeA[2];
    int pipeB[2];

    pipe(pipeA);
    pipe(pipeB);

    int pidA,pidB,pidC;

    if(pidA = fork())
    {
            close(pipeA[0]);
            dup2(pipeA[1],1);
            close(pipeA[1]);
            execlp("ls","ls","/bin",NULL);
            printf("error\n");
    }

    if(pidB = fork())
    {
            close(pipeA[1]);
            dup2(pipeA[0],0);
            close(pipeA[0]);

            close(pipeB[0]);
            dup2(pipeB[1],1);
            close(pipeB[1]);
            execlp("grep","grep","grep",NULL);
            printf("error\n");
    }

    if(pidC = fork())
    {
            close(pipeB[1]);
            dup2(pipeB[0],0);
            close(pipeB[0]);
            execlp("grep","grep","b",NULL);
            printf("error");
    }


    while(pidA != wait(0)){}

    return 0;
}

You aren't closing enough file descriptors. 您没有关闭足够的文件描述符。

/* Semi-working code */
int main()
{
    int pipeA[2];
    int pipeB[2];

    pipe(pipeA);
    pipe(pipeB);

    int pidA,pidB,pidC;

    if (pidA = fork())
    {
            close(pipeB[0]);  // "ls" is not going to use the second pipe
            close(pipeB[1]);  // Ditto
            close(pipeA[0]);
            dup2(pipeA[1], 1);
            close(pipeA[1]);
            execlp("ls", "ls", "/bin", (char *)NULL);
            fprintf(stderr, "error executing 'ls'\n");
            exit(1);
    }

    if (pidB = fork())
    {
            close(pipeA[1]);
            dup2(pipeA[0],0);
            close(pipeA[0]);
            close(pipeB[0]);
            dup2(pipeB[1],1);
            close(pipeB[1]);
            execlp("grep", "grep", "grep", (char *)NULL);
            fprintf(stderr, "error execing 'grep grep'\n");
            exit(1);
    }

    if (pidC = fork())
    {
            close(pipeA[0]);  // The second grep is not going to use the first pipe
            close(pipeA[1]);  // Ditto
            close(pipeB[1]);
            dup2(pipeB[0],0);
            close(pipeB[0]);
            execlp("grep", "grep", "b", (char *)NULL);
            fprintf(stderr, "error execing 'grep b'\n");
            exit(1);
    }

    close(pipeA[0]);  // The parent process is not using the pipes at all
    close(pipeA[1]);
    close(pipeB[0]);
    close(pipeB[1]);

    while (pidA != wait(0))
        ;

    return 0; 
}

Because you didn't close pipeA in the second grep , you end up with the first grep waiting for input from the pipe the second grep still has open, even though the process will not write to it. 因为您没有在第二个grep关闭pipeA ,所以最后一个第一个grep等待来自第二个grep仍然打开的管道的输入,即使该进程不会对其进行写入。 Because of that, the first grep does not finish, so the second doesn't finish either - even though the ls does complete. 因此,第一个grep不会完成,因此第二个grep也不会完成-即使ls已经完成。 These comments would apply even if the parent process closed its copies of the pipes - as the corrected code does. 即使父进程关闭了其管道副本,这些注释也将适用-就像更正后的代码一样。

Notice how you end up closing all 4 descriptors returned by the two calls to pipe() in each of the four processes - three children and the parent process. 请注意,如何最终关闭四个进程中的每个进程(三个子进程和父进程pipe()的两次调用pipe()返回的所有4个描述符。

This leaves one residual problem - the process hierarchy is upside down because of your aconventional use of if (pidA = fork()) . 这留下了一个残留的问题-由于您常规使用if (pidA = fork())因此流程层次结构颠倒了。 You have a child process waiting for its parents. 您有一个子进程正在等待其父进程。 You need to use: 您需要使用:

if ((pidA = fork()) == 0)
{
    /* Be childish */
}

Similarly for each of the other two processes. 其他两个过程中的每个过程类似。 You should also check the pipe() calls and the fork() calls for failure, just to be sure. 为了确保安全,您还应该检查pipe()调用和fork()调用是否失败。

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

static void err_exit(const char *format, ...);

/* Working code */
int main(void)
{
    int pipeA[2];
    int pipeB[2];

    if (pipe(pipeA) != 0 || pipe(pipeB) != 0)
        err_exit("Failed to create a pipe\n");

    int pidA,pidB,pidC;

    if ((pidA = fork()) < 0)
        err_exit("Failed to fork (A)\n");
    else if (pidA == 0)
    {
            close(pipeB[0]);  // "ls" is not going to use the second pipe
            close(pipeB[1]);  // Ditto
            close(pipeA[0]);
            dup2(pipeA[1], 1);
            close(pipeA[1]);
            execlp("ls", "ls", "/bin", (char *)NULL);
            err_exit("error executing 'ls'\n");
    }

    if ((pidB = fork()) < 0)
        err_exit("failed to fork (B)\n");
    else if (pidB == 0)
    {
            close(pipeA[1]);
            dup2(pipeA[0],0);
            close(pipeA[0]);
            close(pipeB[0]);
            dup2(pipeB[1],1);
            close(pipeB[1]);
            execlp("grep", "grep", "grep", (char *)NULL);
            err_exit("error execing 'grep grep'\n");
    }

    if ((pidC = fork()) < 0)
        err_exit("failed to fork (C)\n");
    else if (pidC == 0)
    {
            close(pipeA[0]);  // The second grep is not going to use the first pipe
            close(pipeA[1]);  // Ditto
            close(pipeB[1]);
            dup2(pipeB[0],0);
            close(pipeB[0]);
            execlp("grep", "grep", "b", (char *)NULL);
            err_exit("error execing 'grep b'\n");
    }

    close(pipeA[0]);  // The parent process is not using the pipes at all
    close(pipeA[1]);
    close(pipeB[0]);
    close(pipeB[1]);

    while (wait(0) != -1)
        ;

    printf("Continuing here...\n");
    sleep(3);
    printf("That's enough of that!\n");

    return 0; 
}

static void err_exit(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    exit(1);
}

When doctored to use /usr/bin instead of /bin , this program works OK on Mac OS X 10.7.3. 当尝试使用/usr/bin代替/bin ,此程序在Mac OS X 10.7.3上可以正常运行。 It lists three files and then generates the message about 'Continuing here': 它列出了三个文件,然后生成有关“在此处继续”的消息:

bzegrep
bzfgrep
bzgrep
Continuing here...
That's enough of that!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM