system() 函数与fork() 和 exec() 一起启动了一个程序。管道也有一对类似的函数: popen() 和 pclose()
popen() 和 pclose() 的原型是:
#include <stdio.h>
FILE *popen (const char *command, const char *mode)
int pclose (FILE *stream)
popen() 函数在调用进程和 command 指定的程序之间创建一个管道。实际上是当前进程先 fork 出一个子进程,然后该子进程再调用 exec 函数族中的函数去执行 command ,同时还使用 pipe() 建立了一个连通进程和 command 的一个管道。调用进程既可以从管道读取也可以写入管道,这由 mode 参数决定。当 mode 为 'r' 时为进程读 command 的输出结果;如果 mode 为 'w' 时,表示进程给 command 输送些参数。在 glibc2.9 后增加了一个 'e' 选项,该选项相当于设置了 FD_CLOEXEC 选项,也就是说,command 不会用到进程里的文件描述符。
函数返回的是普通的标准 I/O 流指针,通过它可以将需要处理的内容输送到 shell 命令进行处理。如果函数执行失败(可能是内部调用 fork() 或 pipe() 失败,抑或无法分配相应内存空间),则返回 NULL 。
最后,需要调用 pclose() 函数以等待相应进程结束及 command 的的退出状态码。
测试代码:
[C++] 纯文本查看 复制代码 #include <stdio.h>
#include <stdlib.h>
#define MAXSTR 5
int main(void)
{
int i;
FILE *pipe_fp;
char *strings[MAXSTR] = {"hello", "www", "groad", "net", "good"};
if ((pipe_fp = popen("sort", "w")) == NULL) {
perror("popen");
exit(EXIT_FAILURE);
}
for (i = 0; i < MAXSTR; i++) {
fputs(strings[i], pipe_fp);
fputc('\n', pipe_fp);
}
pclose(pipe_fp);
return (0);
}
运行输出:beyes@beyes :~/c/popen> ./popen
good
groad
hello
net
www 上面程序,我们将要排序的字符串通过通用 popen() 返回的 I/O 流指针输送往 command 一侧,然后用 sort 命令进行排序。需要注意的是,popen() 绑定的是一个 shell,因此可以在执行的命令中使用各种扩展匹配符号及重定向符号,如我们将上面的 popen() 改成:popen("sort > /tmp/popen.txt", "w") ,那么在执行程序后,可以看到结果保存在 /tmp/popen.txt 中。
下面这个例子,创建了两个两个管道,一个用以读,一个用以写,模拟了一种全双工的工作情形:
[C++] 纯文本查看 复制代码
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *pipe_in, *pipe_out;
char readbuf[128];
if ((pipe_in = popen("ls", "r")) == NULL) {
perror("popen");
exit(EXIT_FAILURE);
}
if ((pipe_out = popen("sort", "w")) == NULL) {
perror("popen");
exit(EXIT_FAILURE);
}
if (( pipe_out = popen("sort", "w")) == NULL) {
perror("popen");
exit(EXIT_FAILURE);
}
while (fgets(readbuf, 128, pipe_in))
fputs(readbuf, pipe_out);
pclose(pipe_in);
pclose(pipe_out);
return (0);
}
运行输出:beyes@beyes :~/c/popen> ./popen2
popen
popen2
popen2.c
popen.c |