【问题标题】:Unable to use pipe as input for grep in C无法使用管道作为 C 中 grep 的输入
【发布时间】:2016-11-30 14:04:57
【问题描述】:

在 Ubuntu 16 上,我正在尝试编写一个执行管道、分叉和​​执行的程序:

  • 程序将通过命令行参数接受文件名;
  • 子进程将打开命名文件并执行cat将内容传输到第二个子进程;和
  • 第二个子进程将执行grep 以选择包含数字的行以转发到第三个子进程
  • 第三个子进程打印接收到的行。

这是我的代码:

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

#define BLOCK_SIZE 4096

int main(int argc, char** argv)
{
    int PID;
    int pipe1[2];
    int pipe2[2];
    int pipe3[2];
    char fileName[256];
    int lengthfileName = strlen(argv[1]);
    char content[BLOCK_SIZE];
    char modifiedContent[BLOCK_SIZE];
    int file;
    if(argc < 2)
    {
        printf("Usage prog file\n");
        exit(1);
    }
    if(pipe(pipe1) < 0)
    {
        printf("Error at pipe\n");
        exit(1);
    }
    if(pipe(pipe2) < 0)
    {
        printf("Error at pipe\n");
        exit(1);
    }
    if(pipe(pipe3) < 0)
    {
        printf("Error at pipe\n");
        exit(1);
    }
    if((PID = fork()) < 0)
    {
        printf("Error at process\n");
        exit(1);
    }


    if(PID == 0) //first child
    {
        close(pipe1[1]);
        read(pipe1[0],fileName,lengthfileName); 
        close(pipe1[0]);

        close(pipe2[0]); 
        dup2(pipe2[1],1);
        close(pipe2[1]); 
        execlp("/bin/cat","cat",fileName,NULL);


        exit(0);
    }
    else // parent
    {
        close(pipe1[0]); 
        write(pipe1[1],argv[1],lengthfileName);
        close(pipe1[1]);

        int status;

        if((PID = fork()) < 0)
        {
        printf("Error at process\n");
        exit(1);
        }
        if(PID == 0) // child 2
        {
            close(pipe2[1]);
            //read(pipe2[0],content,BLOCK_SIZE);
            //dup2(pipe2[0],0);// ***********************MARKED LINE HERE *****************************************
            close(pipe2[0]);    

            close(pipe3[0]);
            dup2(pipe3[1],1);
            close(pipe3[1]);    

            execlp("grep","grep","[0-9]",NULL);

            exit(0);

        }

        if((PID = fork()) < 0)
        {
            printf("Error at process\n");
            exit(1);
        }
        if(PID == 0) //cod fiu 2
        {
            close(pipe3[1]);
            read(pipe3[0],modifiedContent,BLOCK_SIZE);
            close(pipe3[0]);
            printf("GOT FROM PIPE:%s",modifiedContent);
            exit(0);
        }
        waitpid(PID, &status, 0);
    }

    return 0;
}

我的问题在子进程 2 代码中,我尝试使用管道作为 grep 的输入。如图所示,输入来自终端;如果我取消注释标记的行,则程序挂起,我必须手动终止它以使其停止。

我在子进程 2 中使用 pipe2grep 提供数据的方式有什么问题?还是其他地方有问题?

【问题讨论】:

  • 第一个孩子的一个主要问题是numeFisier 不包含null 终止 字符串。
  • 如果代码是英文的会很有帮助:) @Someprogrammerdude Joachim 你真棒,等待你的回答
  • @Someprogrammerdude 我不明白为什么这是个问题,我只在孩子一号的 2 个功能中使用它并且文件打开没问题,我的意思是孩子一号将文件内容完美发送到孩子 2
  • @VinayShukla 对不起,我翻译了代码:)
  • 如果一个字符串没有终止,你将有未定义的行为。它似乎起作用只是侥幸。它可能会在您最意想不到的时候停止工作。

标签: c grep pipe fork dup2


【解决方案1】:

通过管道将文件名传输给第一个子文件有点愚蠢,但依赖于该子文件从其父文件继承其长度。如果您要继承名称的长度,那么您不妨继承整个文件名,省去第一个管道。

您可以想象首先通过管道发送(固定大小的)长度值以避免继承它,但这样的方案是没有意义的——不仅分叉的子进程从它们的父进程继承数据,您也无法避免依赖它在你的程序中。特别是,子节点必须从父节点继承开放的管道末端和管道文件描述符数组,以使单父方法完全起作用。

还请注意,您(可能)幸运地通过管道接收到的文件名以空值终止。第一个孩子既不会从管道中读取它,也不会显式设置它。

但主要问题似乎是您有杂散的开口管端。在派生任何子代之前,您在父代中创建所有三个管道。因此,在每个分叉处,子级将继承父级尚未关闭的 all 管道端的打开文件描述符。子进程应该关闭它们不使用的所有打开的管道末端,但它们只关闭其中的一些。诸如grep(和cat)之类的程序在看到文件末尾之前不会退出,并且当 any 进程保持写端打开时,他们不会在管道上看到它.

具体来说,父进程从不关闭pipe2的写端,实际上第三个子进程继承了那个打开的描述符,也没有关闭它。第一个子节点在退出时关闭该 FD 的副本,但在管道端的另外两个句柄打开时,该端保持打开状态。因此,当第二个孩子从该管道获取输入时,它永远不会看到文件结尾,也永远不会退出。在分叉第二个孩子和分叉第三个孩子之间让父母关闭pipe2 的两端应该可以解决这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    相关资源
    最近更新 更多