Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C程序模拟命令行提示符_C_Pipe - Fatal编程技术网

C程序模拟命令行提示符

C程序模拟命令行提示符,c,pipe,C,Pipe,我正在尝试实现一个小型C程序,它的执行方式类似于Linux shell命令提示符$sort

我正在尝试实现一个小型C程序,它的执行方式类似于Linux shell命令提示符
$sort
。为此,我使用execlp来运行命令

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

我发布了我的代码,在我编译了
gcc-o sortuniqwc sortuniqwc.c
并运行了
/sortuniqwc
之后,它就挂断了。如果我注释掉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");
}
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,char*arv[]
{
pid_t pid;
int fd1[2];//生成文件描述符1
如果(管道(fd1)=-1)
{
fprintf(标准“管道故障”);
返回1;
}
pid=fork();//排序的第一个子级
//printf(“管道父pid为%d,子pid为%d”,getppid(),getpid());
if(pid<0)
{
fprintf(标准“叉错误”);
返回1;
}
如果(pid==0)
{
dup2(fd1[1],1);
关闭(fd1[0]);
//printf(“运行排序的子进程是%d\n”,getpid());
execlp(“排序”,“排序”,空);
printf(“排序执行器-不应在此处”);
出口(0);
}
等待(0);
int-fd2[2];
如果(管道(fd2)=-1)
{
fprintf(标准“管道故障”);
返回1;
}
pid=fork();//uniq的第二个子项
if(pid<0)
{
fprintf(stderr,“fork error\n”);
返回1;
}
如果(pid==0)
{
dup2(fd1[0],0);
dup2(fd2[1],1);
关闭(fd1[1]);
关闭(fd2[0]);
//printf(“运行uniq的子进程是%d\n”,pid);
execlp(“/usr/bin/uniq”,“uniq”,NULL);
printf(“uniq exec-你不应该在这里”);
出口(0);
}
等待(0);
pid=fork();//wc的第三个子进程
if(pid<0)
{
fprintf(stderr,“fork失败\n”);
返回1;
}
如果(pid==0)
{
dup2(fd2[0],0);
关闭(fd2[1]);
关闭(fd1[0]);
关闭(fd1[1]);
//printf(“运行wc的子进程是%d\n”,getpid());
execlp(“wc”、“wc”、“-l”、NULL);
printf(“wc exec-您不应该在这里\n”);
出口(0);
}
//母公司
关闭(fd1[0]);
关闭(fd1[1]);
关闭(fd2[0]);
关闭(fd2[1]);
等待(空);
printf(“子完整\n”);
}

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

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

此解决方案还要求将整个排序输出缓冲在管道中(即,在内核中)。对于非琐碎的输入,最好按相反的顺序分叉子级,连接它们的所有管道,并让它们并行运行。这更接近于一个真正的、健壮的shell


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

。o o o(YaUs(又一个Un*x shell)这个名字今年多久出现一次?)管道在阻塞进程之前只能保存这么多数据。我认为您需要首先创建所有管道,所有的fork和exec都需要完成,然后主程序需要读取stdin并将其传递给管道。然后,当所有输入处理完成后,您开始关闭管道并等待子进程退出。@Fred父进程不需要读取输入并向下传递,排序子进程可以这样做。。。但你是对的,最好让所有的孩子并行运行,而不是按顺序等待。但对于小输入,这里的问题是父级中未关闭的
fd1
的thr write end的悬空副本。