Linux系统上的popen()库函数

转载地址:https://blog.csdn.net/qq_29344757/article/details/70925123

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

FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
1
2
3
也就是说这两个函数应用于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。
--------------------- 
作者:echo_bright_ 
来源:CSDN 
原文:https://blog.csdn.net/qq_29344757/article/details/70925123 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/kunkliu/article/details/86621415
今日推荐