将子进程的 stdout 和 stderr 重定向到两个命名管道(然后从它们读回)

Posted

技术标签:

【中文标题】将子进程的 stdout 和 stderr 重定向到两个命名管道(然后从它们读回)【英文标题】:Redirecting a child process' stdout and stderr to two named pipes (then reading back from them) 【发布时间】:2011-03-22 12:23:56 【问题描述】:

我正在开发一个应用程序,它 popen()s 另一个进程,其输出 - stderr 和 stderr - 需要重定向到两个命名管道,这两个命名管道也是由应用程序创建的。然后我需要从管道中读回数据。

mkfifo("output.fifo", 0666); // error checks etc.
mkfifo("error.fifo", 0666); // error checks etc.
popen("cstuff 'param' < input.txt 1> output.fifo 2> error.fifo", "r");

不起作用:当我尝试读取 error.fifo 时,应用程序挂起。 sleep()ing / wait()ing 在mkfifo()popen() 之间也不起作用。

// output.txt is the result from a file dialog
popen("cstuff 'param' < input.txt 1> output.txt 2> error.fifo", "r");

确实有效。

popen("cstuff 'param' < input.txt 1> output.fifo", "r");

也可以。

$ cstuff 'param' < input.txt 1> output.txt 2> output.txt

从 shell 也可以(但不是从我的应用程序)。

我找不到一种直接(或任何)方法来读取两个工作的管道。如何实现?

【问题讨论】:

9 为什么这个标签是 'bash'? nhed,因为popen(3) 使用sh -c 执行程序 @sarnold: man 3 popen(至少在我的系统上)说使用了/bin/sh -c,这通常不是 Bash。 @nhed,公平点,这不是密切相关 - 删除标签。 【参考方案1】:

试试system(3) 而不是popen(3);您没有使用从popen(3) 返回的FILE*,因为您没有使用popen(3),因为它本来是要使用的。但这在system(3) 应该可以正常工作。

【讨论】:

虽然在示例中使用 popen() 确实不完全足够,但切换到 system() 并不能解决问题。 (顺便说一句,(3)符号是什么?) Hrm,那么也许 pelya 的答案是正确的。 (3) 表示手册页在第三部分; printf(1)printf(3) 是两个不同的手册页,该部分有助于确定是哪一个。 popen(3) 没那么必要,但旧习惯很难改掉。 :)【参考方案2】:

您应该在 output.fifo 和 error.fifo 的文件描述符上调用 poll() 或 select(),并且只有在数据准备好时才调用 read()。

我建议你使用pstreams 而不是丑陋的命名管道。

【讨论】:

+1:使用 poll() 有助于停止挂起,但是,如果等待 1 秒,poll() 就会返回,根本没有任何事件。 (尝试了所有优先级/正常,读/写变体;当我 $ myapp 1> out.txt 2> err.txt 时,没有明显的等待,所以我假设 1s 应该绰绰有余。)关于我的标准错误要去哪里? (我指的是我将其发送到的文件为 const char *,因此不会出现拼写错误。)

以上是关于将子进程的 stdout 和 stderr 重定向到两个命名管道(然后从它们读回)的主要内容,如果未能解决你的问题,请参考以下文章

如何在使用os.execl替换进程时重定向stdin / stdout / stderr

在C中重定向子进程的文件输出

重定向stdin stdout stderr |

如何从 Raspbian 上的 systemd 服务正确重定向 stdout/stderr?

将stdout和stderr重定向到一个文件,也重定向到linux中的控制台[重复]

输出重定向是不是按顺序写入 stdout 和 stderr 信息?