【问题标题】:Is it possible to implement command substitution via pipeline?是否可以通过管道实现命令替换?
【发布时间】:2021-12-30 16:37:14
【问题描述】:

例如,我们有$(ls):

int pfd[2];
pipe(pfd);
switch (fork()) {
    case 0:
    close(pfd[0]);
    dup2(pfd[1], 1 /*stdout*/);
    exec('ls', 'ls');
    case -1;
    // Report the error...
    break;
    default;
    break;
}
wait(nullptr); // Wait until the process is done (it is better to use the waitpid() version)
// And now we can read from pfd[0]

这段代码非常概念化,但我说的对吗?子进程完成后是否可以从管道的写入端提取数据?剩下的就是将子字符串 ($(ls)) 替换为另一个(ls 本身的结果)。如果我错了,请纠正我。

即使pfd[0] 是一个有效的文件描述符,它指向一个带有ls 执行结果的缓冲区,我们如何安全地从中读取?

【问题讨论】:

    标签: c++ c linux posix system-calls


    【解决方案1】:
    wait(nullptr); 
    

    这将停止父进程,直到子进程终止。

    子进程的标准输出连接到管道的写入端,管道的读取端在父进程中打开。

    管道的内部缓冲区大小是有限的。如果子进程产生足够的输出,它将阻塞直到管道被读取。

    但是父进程现在正在等待子进程终止,然后再执行任何操作。这将导致死锁。

    此外,看起来父进程仍然打开了管道的写入端。如果父进程试图从中读取,并且它读取了所有内容, 将阻塞,因为管道的写入端仍然打开(即使在子进程终止后) )。

    所以,不管你想做什么,都要关闭父进程中管道的写端。

    从那时起,您“在概念上”(如您所问)有几个可用的选项。

    您可以专注于从管道中读取。当管道的写端关闭时,文件结束指示将通知您。子进程已终止,因此您现在可以为它wait(),并获取其立即退出代码。

    这可能是最常见的方法。其他方法也是可能的,例如阅读和关注SIGPIPE。或者在 Linux 上使用信号文件描述符来捕获SIGPIPE,以一种允许从管道读取的方式方便地复用它(通过pollselect)。

    请注意,如果子进程在写入管道后终止,并且父进程有wait() 子进程没有从管道中读取,则在wait() 返回后,可以从管道中读取未读数据。它仍然会在那里。但是,正如我所解释的,这是脆弱的,如果子进程产生足够的输出来堵塞整个管道,它就会中断。

    从管道读取通常要简单得多,直到文件结束指示,然后在子进程之后清理。

    【讨论】:

    • 感谢您的详细解答!说到问题的第二部分,如果从仍在写入的文件描述符中读取最安全的方法呢?
    • 没有“最安全”的方法。只有一种方法可以从文件描述符中读取:从中读取到read()。当只有一种可能的方式从文件描述符中读取时,您没有任何其他选项可供选择。
    猜你喜欢
    • 2016-10-27
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 2014-12-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    相关资源
    最近更新 更多