C程序模拟命令行提示符

时间:2018-11-29 22:00:18

标签: c pipe

我正在尝试实现一个小型C程序,该程序将类似于Linux Shell命令提示符$ sort < Names.txt | uniq | wc - l执行。为此,我正在使用execlp运行命令

结果程序将对名称的任意列表进行排序并删除重复的名称。它对列表进行排序是因为它需要相邻的重复行才能将其删除。然后只计算行数。

我已经发布了我的代码,目前我编译gcc -o sortuniqwc sortuniqwc.c并运行./sortuniqwc < Names.txt后才挂断它。如果我注释掉fd的管道,则每个系统调用似乎都能正常执行。我不确定为什么它不能正确地将进程传递给系统调用

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

int main(int argc, char *arv[])
{
    pid_t pid;
    int fd1[2]; //making file descriptor 1

    if (pipe(fd1) == -1)
    {
        fprintf(stderr, "pipe failed");
        return 1;
    }

    pid = fork(); //first child for sort
    //printf("the pid for pipe parent is %d and the child pid is %d", getppid(), getpid());

    if (pid < 0)
    {
        fprintf(stderr, "fork error");
        return 1;
    }

    if (pid == 0)
    {
        dup2(fd1[1], 1);
        close(fd1[0]);
        //printf("the child process running sort is %d\n", getpid());
        execlp("sort", "sort", NULL);
        printf("sort exec - should not be here");
        exit(0);
    }

    wait(0);

    int fd2[2];

    if (pipe(fd2) == -1)
    {
        fprintf(stderr, "pipe failed");
        return 1;
    }

    pid = fork(); //second child for uniq

    if (pid < 0)
    {
        fprintf(stderr, "fork error\n");
        return 1;
    }

    if (pid == 0)
    {
        dup2(fd1[0], 0);
        dup2(fd2[1], 1);
        close(fd1[1]);
        close(fd2[0]);
        //printf("the child process running uniq is %d\n", pid);
        execlp("/usr/bin/uniq", "uniq", NULL);
        printf("uniq exec - you shouldnt be here");
        exit(0);
    }

    wait(0);

    pid = fork(); //3rd child process for wc

    if (pid < 0)
    {
        fprintf(stderr, "fork failed\n");
        return 1;
    }

    if (pid == 0)
    {
        dup2(fd2[0], 0);
        close(fd2[1]);
        close(fd1[0]);
        close(fd1[1]);
        //printf("the child process running wc is %d\n", getpid());
        execlp("wc", "wc", "-l", NULL);
        printf("wc exec - you shouldnt be here\n");
        exit(0);
    }
    //parent

    close(fd1[0]);
    close(fd1[1]);
    close(fd2[0]);
    close(fd2[1]);

    wait(NULL);

    printf("CHILD COMPLETE \n");
}

1 个答案:

答案 0 :(得分:1)

TL; DR-父级需要close()附加到sort的输出的管道写端副本。在第一次等待之前添加close(fd1[1])可以“解决”该问题。

程序在对wait()的第二次调用中“挂起”(等待uniq子项退出 1 )。但是,uniq永远不会退出,因为它的标准输入连接到fd1管道的读取端,并且永远不会关闭。系统中此文件描述符有两个副本:第一个副本属于exec的{​​{1}}的子进程,并且确实按sort的预期关闭了。但是另一个副本属于不sort的父进程。由于管道的写入端仍然至少有一个打开的文件描述符,因此管道不会关闭。

此解决方案还要求将 entire 排序输出缓冲在管道中(即内核中)。对于非平凡的输入,最好以相反的顺序分叉子节点,连接它们的所有管道,并让它们并行运行。这更接近于真实,强大的外壳程序。

1 或接收信号等,坚固的外壳应检查该信号。