我很困惑popen()如何在unix中重定向子进程的stdin,stdout和stderr . 关于popen()的手册页在这方面不是很清楚 . 电话
FILE *p = popen("/usr/bin/foo", "w");
分叉子进程并执行带参数“-c”,“/ usr / bin / foo”的shell,并重定向此shell的stdin(重定向foo的stdin),stdout到p . 但是stderr会发生什么?它背后的一般原则是什么?
我注意到,如果我在foo中打开一个文件(使用fopen,socket,accept等),并且父进程没有stdout,它会被分配下一个可用的文件号,即1,依此类推 . 这会从fprintf(stderr,...)等调用中产生意外结果 .
写作可以避免
FILE *p = popen("/usr/bin/foo 2>/dev/null", "w");
在父计划中,但他们是更好的方法吗?
5 回答
popen(3)
只是一个库函数,它依赖于fork(2)
和pipe(2)
来完成实际工作 .但是
pipe(2)
只能创建单向管道 . 要发送子进程输入,并捕获输出,您需要打开两个管道 .如果你想捕获
stderr
,'s possible, but then you'll需要 three 管道,select
循环来仲裁stdout
和stderr
流之间的读取 .双管道版本有一个示例here .
简单的想法:为什么不在命令字符串中添加“2>&1”以强制bash将stderr重定向到stdout(好吧,写入stdin仍然是不可能的,但至少我们得到stderr和stdout进入我们的C程序) .
从其手册页,它允许您读取命令标准输出或写入其标准输入 . 它没有说明stderr . 因此,不会重定向 .
如果你提供“w”,你将把你的东西发送到执行的shell的stdin . 这样做
将使shell执行/ bin / cat,并将字符串
"hello"
作为其标准输入流传递给它 . 如果要在执行上面的代码之前将stderr重定向到文件"foo"
首先执行此操作:它将打开文件,并将其文件描述符复制到2,然后关闭原始文件描述符 .
现在,如果您的父节点中关闭了stdout,那么如果子节点调用
open
它将获得1,因为那是(如果stdin已经打开)下一个空闲文件描述符 . 我看到的唯一解决方案就是使用dup2并将一些内容复制到父内容中,就像上面的代码一样 . 请注意,如果子项打开stdout
,它也不会在父项中打开stdout
. 它在那里保持关闭 .查看Bart Trojanowski的popenRWE . 干净的方式做所有3管道 .
如果您只想获得STDERR,请尝试以下方法:
你会得到这个: