c语言中的pipe()和fork()

c语言中的pipe()和fork(),c,fork,pipe,C,Fork,Pipe,我需要创建两个子进程。一个子进程需要运行命令“ls-al”,并将其输出重定向到下一个子进程的输入,下一个子进程将对其输入数据运行命令“sort-r-n-k5”。最后,父进程需要读取该数据(已排序的数据)并将其显示在终端中。终端中的最终结果(在执行程序时)应该与我直接在shell中输入以下命令相同:“ls-al | sort-r-n-k5”。为此,我需要使用以下方法:pipe()、fork()、execlp() 我的程序可以编译,但是我没有得到想要的输出到终端。我不知道怎么了。代码如下: #inc

我需要创建两个子进程。一个子进程需要运行命令“ls-al”,并将其输出重定向到下一个子进程的输入,下一个子进程将对其输入数据运行命令“sort-r-n-k5”。最后,父进程需要读取该数据(已排序的数据)并将其显示在终端中。终端中的最终结果(在执行程序时)应该与我直接在shell中输入以下命令相同:“ls-al | sort-r-n-k5”。为此,我需要使用以下方法:pipe()、fork()、execlp()

我的程序可以编译,但是我没有得到想要的输出到终端。我不知道怎么了。代码如下:

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

int main()
{
    int fd[2];
    pid_t ls_pid, sort_pid;
    char buff[1000];

    /* create the pipe */
    if (pipe(fd) == -1) {
        fprintf(stderr, "Pipe failed");
        return 1;
    }

    /* create child 2 first */
    sort_pid = fork();
    if (sort_pid < 0) {                         // error creating Child 2 process
        fprintf(stderr, "\nChild 2 Fork failed");
        return 1;
    }
    else if(sort_pid > 0) {                     // parent process

        wait(NULL);                             // wait for children termination

        /* create child 1 */
        ls_pid = fork();
        if (ls_pid < 0) {                       // error creating Child 1 process
            fprintf(stderr, "\nChild 1 Fork failed");
            return 1;
        }
        else if (ls_pid == 0) {                 // child 1 process
            close(1);                           // close stdout
            dup2(fd[1], 1);                     // make stdout same as fd[1]
            close(fd[0]);                       // we don't need this end of pipe
            execlp("bin/ls", "ls", "-al", NULL);// executes ls command
        }

        wait(NULL);
        read(fd[0], buff, 1000);                // parent reads data 
        printf(buff);                           // parent prints data to terminal   
    }
    else if (sort_pid == 0) {                   // child 2 process
        close(0);                               // close stdin
        dup2(fd[0], 0);                         // make stdin same as fd[0]
        close(fd[1]);                           // we don't need this end of pipe
        execlp("bin/sort", "sort", "-r", "-n", "-k", "5", NULL); // executes sort operation
    }

    return 0;
}
#包括
#包括
#包括
#包括
int main()
{
int-fd[2];
pid_t ls_pid,sort_pid;
字符增益[1000];
/*创建管道*/
如果(管道(fd)=-1){
fprintf(标准“管道故障”);
返回1;
}
/*首先创建子2*/
sort_pid=fork();
if(sort_pid<0){//创建子进程2时出错
fprintf(stderr,“\n归档2 Fork失败”);
返回1;
}
如果(sort_pid>0){//父进程
等待(NULL);//等待子项终止
/*创建子1*/
ls_pid=fork();
如果(ls_pid<0){//创建子进程1时出错
fprintf(stderr,“\n归档1 Fork失败”);
返回1;
}
如果(ls_pid==0){//子进程1
关闭(1);//关闭标准输出
dup2(fd[1],1);//使标准输出与fd[1]相同
close(fd[0]);//我们不需要管道的这一端
execlp(“bin/ls”、“ls”、“-al”、NULL);//执行ls命令
}
等待(空);
读取(fd[0],buff,1000);//父级读取数据
printf(buff);//父对象将数据打印到终端
}
如果(sort_pid==0){//子进程2
close(0);//关闭stdin
dup2(fd[0],0);//使stdin与fd[0]相同
close(fd[1]);//我们不需要管道的这一端
execlp(“bin/sort”、“sort”、“-r”、“-n”、“-k”、“5”、NULL);//执行排序操作
}
返回0;
}

您的父进程在创建ls进程之前,请等待排序进程完成

排序过程需要先读取其输入,然后才能完成。它的输入来自ls,在
等待之后才会启动。僵局

您需要创建这两个进程,然后等待它们

此外,您的文件描述符操作也不太正确。在这对调用中:

close(0);
dup2(fd[0], 0);
关闭是多余的,因为如果存在fd 0,dup2将自动关闭现有fd 0。您应该在dup2之后执行
close(fd[0])
,这样您只有一个文件描述符绑定到管道的那一端。如果你想变得真正健壮,你应该测试wither
fd[0]==0
,在这种情况下,跳过dup2并关闭

将所有这些应用于其他dup2

然后是父进程保持管道打开的问题。我想说,在你把管道的两端传递给孩子们之后,你应该关闭管道的两端,但是在最后一次
等待之后,你有一个奇怪的
读取
from
fd[0]
。。。我不知道为什么会这样。如果
ls | sort
管道已正确运行,则管道随后将为空,因此将无需读取任何内容。在任何情况下,您都必须在父级中关闭
fd[1]
,否则排序过程将无法完成,因为在关闭所有写入程序之前,管道不会指示EOF

奇怪的
读取之后
是一个可能会崩溃的
printf
,因为读取缓冲区不会被
'\0'
-终止


使用
execlp
的要点是它为您执行
$PATH
查找,因此您不必指定
/bin/
。我的第一次测试运行失败,因为我的排序在
/usr/bin/
中。为什么不必硬编码路径?

除非您是从
/
执行,否则请尝试将“bin/ls”替换为“/bin/ls”(类似于“/bin/sort”),否则您似乎没有进行错误检查。您应该添加一些,这将帮助您诊断问题。如果没有“/”,它会向我显示两个子语句,但当我放置“/”时,它不会显示这些语句;这就像它没有到达子块一样。顺便说一句:如果路径名中没有“/”,则execlp()和execvp()执行路径搜索。这些都可以在精细手册中阅读。它们还可以返回(错误时)检查返回值,如果返回,则检查errno。该疾病从何处开始,在字符串的开头而不是结尾打印换行符,如在
fprintf(stderr,“\nChild 2 Fork failed”)?非常感谢您;我现在让它工作了。我在dup2之前取出了多余的闭合器;在最后一次等待()之后,我还从df[0]中取出read()。我意识到这是没有必要的。我在sort块中添加了一个open(1)语句,以便在终端中显示sort的输出,最后我取出了buff变量和最后一个printf,因为它们不需要。哦!,我只在两个子进程之后执行等待(NULL)。