前言:
Unix 界有一句名言:“一行shell脚本胜过万行C程序”。比如实现一个 ping程序来测试网络的连通性,实现ping函数需要写上200~300行代码,为什么不能直接调用系统的ping命令呢?通常在程序中通过 system函数来调用shell命令。但是,system函数仅返回命令是否执行成功,而我们可能需要获得shell命令在控制台上输出的结果。例如,执行外部命令ping后,如果执行失败,我们希望得到ping的返回信息。
正文:
本教程仅提供使用popen的方法,这种方法最实用。其它方法请参考 linux C程序中调用shell终端的命令
在学习unix编程的过程中,系统提供了一个popen函数,可以非常简单的处理调用shell,其函数原型如下:
FILE *popen(const char *command, const char *type);
该函数的作用是创建一个管道,fork一个进程,然后执行shell,而shell的输出可以采用读取文件的方式获得。采用这种方法,既避免了创建临时文件,又不受输出字符数的限制,推荐使用。
popen使用FIFO管道执行外部程序。
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
popen 通过type是r还是w确定command的输入/输出方向,r和w是相对command的管道而言的。r表示command从管道中读入,w表示 command通过管道输出到它的stdout,popen返回FIFO管道的文件流指针。pclose则用于使用结束后关闭这个指针。
下面看一个例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <math.h>
struct timeval tpstart,tpend,delay;
unsigned int delayTimeval=100;//设定100ms延时
float timeuse;
int main( void )
{
FILE *stream;//数据流指针
FILE *wstream;
char buf[1024];
memset( buf, '\0', sizeof(buf) );//初始化buf,以免后面写如乱码到文件中
stream = popen( "ls -l", "r" ); //将“ls -l”命令的输出 通过管道读取(“r”参数)到FILE* stream
if(NULL != stream)
{
wstream = fopen( "test_popen.txt", "w+"); //新建一个可写的文件
gettimeofday(&tpstart,NULL);
fread( buf, sizeof(char), sizeof(buf), stream); //将刚刚FILE* stream的数据流读取到buf中
gettimeofday(&tpend,NULL);
timeuse = 1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;//单位:微妙
if(delayTimeval*1000 > timeuse)
delay.tv_usec = delayTimeval*1000 - timeuse;
else
delay.tv_usec = 0;
timeuse /=1000000;//单位:秒
printf("%f sec\n",timeuse);
fwrite( buf, 1, sizeof(buf), wstream );//将buf中的数据写到FILE *wstream对应的流中,也是写到文件中
}
else
printf("失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
pclose( stream );//popen()由pclose()来关闭
fclose( wstream );//fopen()由fclose()来关闭
return 0;
}
参考文章:
[1]linux C程序中调用shell终端的命令
@本文作者:LeatherWang