将子进程的 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
如何从 Raspbian 上的 systemd 服务正确重定向 stdout/stderr?