13.2 进程管道
可能最简单的在两个程序之间传递数据的方法就是使用popen和pclose函数了。它们的原型如下所示:
1.popen函数
popen函数允许一个程序将另一个程序作为新进程来启动,并可以传递数据给它或者通过它接收数据。command字符串是要运行的程序名和相应的参数。open_mode必须是“r”或者“w”。
如果open_mode是“r”,被调用程序的输出就可以被调用程序使用,调用程序利用popen函数返回的FILE*文件流指针,就可以通过常用的stdio库函数(如fread)来读取被调用程序的输出。如果open_mode是“w”,调用程序就可以用fwrite调用向被调用程序发送数据,而被调用程序可以在自己的标准输入上读取这些数据。被调用的程序通常不会意识到自己正在从另一个进程读取数据,它只是在标准输入流上读取数据,然后做出相应的操作。
每个popen调用都必须指定“r”或“w”,在popen函数的标准实现中不支持任何其他选项。这意味着我们不能调用另一个程序并同时对它进行读写操作。popen函数在失败时返回一个空指针。如果想通过管道实现双向通信,最普通的解决方法是使用两个管道,每个管道负责一个方向的数据流。
2.pclose函数
用popen启动的进程结束时,我们可以用pclose函数关闭与之关联的文件流。pclose调用只在popen启动的进程结束后才返回。如果调用pclose时它仍在运行,pclose调用将等待该进程的结束。
pclose调用的返回值通常是它所关闭的文件流所在进程的退出码。如果调用进程在调用pclose之前执行了一个wait语句,被调用进程的退出状态就会丢失,因为被调用进程已结束。此时,pclose将返回-1并设置errno为ECHILD。
实 验 读取外部程序的输出
现在来看一个简单的popen和pclose示例程序popen1.c。我们将在程序中用popen访问uname命令给出的信息。命令uname-a的作用是打印系统信息,包括计算机型号、操作系统名称、版本和发行号,以及计算机的网络名。
完成程序的初始化工作后,打开一个连接到uname命令的管道,把管道设置为可读方式并让read_fp指向该命令的输出。最后,关闭read_fp指向的管道。
运行这个程序,我们将看到如下所示的输出结果(这是在本书其中一位作者的机器上的输出结果):
实验解析
这个程序用popen调用启动带有-a选项的uname命令。然后用返回的文件流读取最多BUFSIZ个字符(这个常量是在stdio.h中用#define语句定义的)的数据,并将它们打印出来显示在屏幕上。因为我们是在程序内部捕获uname命令的输出,所以可以处理它。