函数作用
如果说system在一定程度上是execl的优化版,那么popen就一定程度上是system的优化版,使用popen不仅可以运行代码,还可以获取运行的输出结果(但是system和exec族函数还是非常重要的,也有自己的特定应用场景)。
并且popen函数使用到了管道的概念(之后会详细学习):
" popen()函数通过创建一个管道,调用fork()产生一个子进程,执行一个shell以运行命令来开启一个进程。这个管道必须由pclose()函数关闭,而不是fclose()函数。pclose()函数关闭标准I/O流,等待命令执行结束,然后返回shell的终止状态。如果shell不能被执行,则pclose()返回的终止状态与shell已执行exit一样。"
需要添加的库
#include <stdio.h>
函数原型
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
函数参数
- command:是一个指向以NULL结束的shell命令字符串的指针。这行命令将被传到bin/sh并使用-c标志,shell将执行这个命令
- type:只能是读或者写中的一种,得到的返回值(标准I/O流)也具有和type相应的只读或只写类型。如果type是"r"则文件指针连接到command的标准输出;如果type是"w"则文件指针连接到command的标准输入,如果想要实现类似system功能,此处应该是"r"
- 返回值:如果调用fork()或pipe()失败,或者不能分配内存将返回NULL,否则返回标准I/O流。popen()没有为内存分配失败设置errno值。如果调用fork()或pipe()时出现错误,errno被设为相应的错误类型。如果type参数不合法,errno将返回EINVAL。
实操演示
demo6.c:
根据上面所说,fopen返回的是一个文件流(FILE *型),那么如果想要读取流的数据其实就是使用之前学到的fread函数,详见:
使用fopen等标准C库来操作文件_mjmmm的博客-CSDN博客
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
char ret[1024] = {0};
FILE *fp;
fp = popen("ls -l","r");
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread(&ret, sizeof(char), 1024, fp);
printf("return value of ls = %s\n",ret);
pclose(fp);
return 0;
}
运行代码:
虽然实现的效果似乎和之前没什么区别,但其实很不一样,system或execl调用后只能将结果打印在屏幕上,结果的数据是无法保存的,而popen的结果是可以保存的,之所以打到屏幕上是我使用了printf,如果我不使用printf而是将这些数据写入其他文件或进行其他操作,那么system和execl就无法做到了。