转载地址:https://blog.youkuaiyun.com/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);
也就是说这两个函数应用于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_
来源:优快云
原文:https://blog.youkuaiyun.com/qq_29344757/article/details/70925123
版权声明:本文为博主原创文章,转载请附上博文链接!