c - 将 bash 命令 echo 和 bc 管道化到 C 程序中

标签 c pipe fork dup2 execl

我正在尝试编写一个小 C 程序来实现两个 bash 命令的管道:echo $arithmeticOperation | BC

$arithmeticOperation 是一个作为输入的字符串。

程序在执行第一个命令时工作正常,但是当我运行第二个命令时,我得到了正确的输出,但执行 bc 的子进程仍然卡住,阻止子进程结束。

因此,在这一行中,父进程被阻止: waitpid(pid2,NULL,0);

您认为问题可能出在哪里?

抱歉,如果我问错了问题,这是我的第一个问题。谢谢。



    #define SYSCALL(r,c,e) if((r=c)==-1) { perror(e);exit(EXIT_FAILURE);}

    int main(){
        char buf[128];
        int pfd[2],err;
        pid_t pid1,pid2;
        SYSCALL(err,pipe(pfd),"pipe");
        switch (pid1=fork()) {
            case -1: { perror("fork"); exit(EXIT_FAILURE);}
            case 0 : { 
                scanf("%s",buf);
                SYSCALL(err,dup2(pfd[1],1),"dup");
                close(pfd[1]);
                close(pfd[0]);
                execl("/bin/echo","echo",buf,(char *)NULL);
                return 1;
            }   
        }   
        switch (pid2=fork() ){
             case -1 : { perror("fork"); exit(EXIT_FAILURE);}
             case 0 : { 
                 SYSCALL(err,dup2(pfd[0],0),"dup");
                 close(pfd[1]);
                 close(pfd[0]);
     //          execl("/usr/bin/bc","bc",(char *)NULL);
                 execlp("bc","bc",(char *)NULL);
                return 1;
            }   
        }   
    printf("waiting . . . \n");
    waitpid(pid1,NULL,0);
    printf("wait\n");
    waitpid(pid2,NULL,0);
    close(pfd[1]);
    close(pfd[0]);
    return 0;
    }

因此,如果我将“1+1”作为输入字符串,我会得到正确的输出,但执行 bc 的进程永远不会退出

最佳答案

正如我在 comment 中指出的那样,您的父进程必须在等待 bc 之前关闭管道的文件描述符(并且您已经同意这可以解决问题)。

出现这种情况是因为 bc 打开了管道以进行读取,并且父级打开了管道以进行写入,并且内核认为父级因此可以将数据发送到 bc。虽然不会,但可以。

管理管道时必须非常小心。您小心地避免了未关闭子级中足够的文件描述符的常见问题。

<小时/>

经验法则:如果您 dup2() 将管道的一端连接到标准输入或标准输出,关闭两者 返回的原始文件描述符 pipe() 尽快地。 特别是,您应该在使用任何之前关闭它们 exec*() 函数族。

如果您使用以下任一方式重复描述符,则该规则也适用 dup() 或者 fcntl()F_DUPFD

<小时/>

我也需要扩展它以覆盖父进程。

如果父进程不打算通过管道与其任何子进程通信,则它必须确保关闭管道的两端,以便其子进程可以在读取时接收 EOF 指示(或获取 SIGPIPE 信号或写入错误)写入时),而不是无限期地阻塞。父级通常应该至少关闭管道的一端——程序在单个管道的两端进行读写是极不寻常的。

关于c - 将 bash 命令 echo 和 bc 管道化到 C 程序中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56187565/

相关文章:

c - 如何在c中使用struct

c - linux 中的闹钟和 sleep

C - 管道和 fork - 奇怪的内存垃圾

c++ - 正确代码 - 带 popen 的非阻塞管道

c - 运行 fork 并打印 hello

c++ - 寻找具有某些品质的完全内存数据库

debugging - Pharo:如何在调试器中查看 newProcess 的发送者?

c - 为什么使用float变量计算和我想的不一样?

c - 使用 fflush(stdin)

c - 在 C 中使用管道和 fork 重定向标准输出