簡體   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'

我在使用dup2使ac程序執行ls /bin | grep grep | grep b等命令時遇到問題 ls /bin | grep grep | grep b ls /bin | grep grep | grep b 當我注釋掉第三個命令和相關管道時,它執行ls /bin | grep grep ls /bin | grep grep很好,但是使用最后一個命令,它會立即返回。 同樣,當我輸入“ ps”時,進程仍在運行。 我認為這是由於我如何關閉管道。 我的代碼如下:

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;
}

您沒有關閉足夠的文件描述符。

/* 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; 
}

因為您沒有在第二個grep關閉pipeA ,所以最后一個第一個grep等待來自第二個grep仍然打開的管道的輸入,即使該進程不會對其進行寫入。 因此,第一個grep不會完成,因此第二個grep也不會完成-即使ls已經完成。 即使父進程關閉了其管道副本,這些注釋也將適用-就像更正后的代碼一樣。

請注意,如何最終關閉四個進程中的每個進程(三個子進程和父進程pipe()的兩次調用pipe()返回的所有4個描述符。

這留下了一個殘留的問題-由於您常規使用if (pidA = fork())因此流程層次結構顛倒了。 您有一個子進程正在等待其父進程。 您需要使用:

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

其他兩個過程中的每個過程類似。 為了確保安全,您還應該檢查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);
}

當嘗試使用/usr/bin代替/bin ,此程序在Mac OS X 10.7.3上可以正常運行。 它列出了三個文件,然后生成有關“在此處繼續”的消息:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM