Linux系统上的popen()库函数

来源:互联网 发布:西门子plc简单编程实例 编辑:程序博客网 时间:2024/05/17 15:58

《Unix环境高级编程》在popen和pclose函数章节说,常见的操作是创建一个连接到另一进程的管道,然后读其输出或向其发生输入,所以标准I/O库为实现这些操作提供了两个函数popen和pclose。这两个函数实现的操作是:创建一个管道,fork一个子进程,关闭管道的不使用端,exec一个shell以执行命令,等待命令终止。
函数的原型:

FILE *popen(const char *command, const char *type);int pclose(FILE *stream);

也就是说这两个函数应用于Linux执行shell命令的场景。函数popen先执行fork,然后调用exec以执行command,并且返回一个要么指向子进程的stdout,要么指向stdin的文件指针:若type是”r”,则文件指针是连接到子进程执行command命令的标准输出,如果type是”w”,则文件指针连接到子进程执行command命令的标准输入。
感觉说再多也没用,直接上例子:
程序要求实现功能:从/etc/group文件中提取root的密码

int main(){    FILE *fpr = NULL, *fpw = NULL;    char buf[256];    int ret;    fpr = popen("cat /etc/group", "r");  //执行完这行代码,标准输出就装满,这里这个标准输出标记为out1,管道指向out1,fpr指向管道的读端    fpw = popen("grep root", "w");       //执行这句代码,会一直去读取标准输出,若标准输出为空,则会阻塞,直到标准输出不为空,执行命令后又                                         //会去指读取标准输出继续执行。这里这个标准输入标记为in2。                                         //管道指向int2,fpw指向管道的写端    while ((ret = fread(buf, 1, sizeof(buf), fpr)) > 0)  //从out1中读取256个字节数据,存放在buf    {        fwrite(buf, 1, ret, fpw);                        //将buf的数据写到int2(此时gerp命令一直在获取int2,直到进行退出)    }    pclose(fpr);    pclose(fpw);}

运行结果:
这里写图片描述
下面讲讲我对popen函数的理解
(1) popen(comm, type)函数会创建一个管道,再fork一个子进程,在子进程中执行execX函数来执行comm命令(因为execX执行新程序后新程序的进程空间会覆盖原进程的进程空间,所以开一个子进程来执行execX家族函数),然后想要返回stdout或者stdin的文件指针(取决于type);
(2) 因为comm命令是通过子进程的执行的,那么stdin或者stdout文件指针也是子进程的进程片空间的,要将其返回给父进程,这就需要管道了;
(3) stdin是供程序写数据的,stdout是供程序读数据的。这里设计的巧妙之处在于,管道的读端跟stdout绑定,管道的写端跟stdin绑定;
这里写图片描述
(4) 读写管道操作的无非就是管道(文件)的fd(文件描述符),这里将fd封装到文件流指针fp中;
(5) popen返回的是stdout,那么type为”r”,表示创建一个管道且该管道文件的读端赋给fpr;
(6) popen返回的是stdin,那么type为”w”,表示创建一个管道且该管道文件的写端赋给fpw;
(7) 这样子,读fpr(管道的读端)等于读子进程的stdout,写fpw(管道的写端)等于写子进程的stdin。

0 0