python里经常通过popen调用系统命令,并获取命令的输出结果,然后进行二次处理,是十分地简便,比如想查看下当前的Linux系统,直接调用shell命令很容易一行就能解决
#!/usr/bin/env python import os print os.popen('cat /etc/issue').read().strip() [lihui@localhost ~]# ./popen.py CentOS release 6.4 (Final) Kernel \r on an \m
虽然代码量很少,实际上还是有一个过程的,C的API也有这个同名函数popen以及pclose,有兴趣的可以查看实现的源代码,大概流程包括下面几步:
1:使用pipe()创建管道
2:使用fork()创建子进程
3:子进程调用execl来执行命令,然后通过管道将结果传给主进程
4:最后主进程等待子进程结束,完成后接收到执行结果,返回
这里是定义:
#include <stdio.h> FILE *popen(const char *command, const char *open_mode); int pclose(FILE *stream_to_close);
popen可以将一个另一个程序作为新进程来启动,而且还可以传递数据给它或者通过它接收数据,参数command字符串就是要运行的程序名,命令和相应的参数,参数open_mode只能选择“r”后者是“w”这两种
如果open_mode是“r”,那么第一个参数被调用程序command的输出就可以被使用,这其实跟上面python将输出的结果打印出来一个意思,此时popen函数返回FILE*文件流指针,就可以通过标准库函数fread来读取command的输出;如果open_mode是“w”,调用程序的就可以通过fwrite向被调用的command来发送数据,而command可以在自己的标准输入上读取这些数据;open_mode只能是“r”或者“w”,因此不能同时进行读写操作
pclose一定会等到popen启动的进程结束之后,才会执行,否则会一直等待;返回值是关闭文件流所在进程的退出码,假如在pclose之前执行了一个wait,那么此时被调用进程就结束了,被调用进程的退出状态就丢失了,那么pclose就返回-1
同上面python脚本一样,打印出linux系统版本
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #define MAXSIZE 100 int main(){ FILE *fd; char buffer[MAXSIZE]; memset(buffer, 0, sizeof(buffer)); fd = popen("cat /etc/issue", "r"); if (fd) { if (fread(buffer, sizeof(char), MAXSIZE, fd) > 0) printf("%s", buffer); pclose(fd); exit(0); } return 0; } [lihui@localhost ~]# ./a.out CentOS release 6.4 (Final) Kernel \r on an \m
上面的例子仅仅是将外部程序的输出给捕获,假如想将输出发送给外部程序,这时候就要修改popen的打开方式了,命令用到了一个od命令,它的作用和用法可以自己搜索一下,格式化输出文件中的数据,比如:
[lihui@localhost ~]# cat lihui.txt Hello World! [lihui@localhost ~]# od -c lihui.txt 0000000 H e l l o W o r l d ! \n 0000015
这样,可以通过popen打开方式为“w”,启动od -c命令,就可以向该命令发送数据,od -c接收到处理,然后就打印到标准输出
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #define MAXSIZE 100 int main(){ FILE *fd; char buffer[MAXSIZE]; sprintf(buffer, "My heart will go on ..."); fd = popen("od -c", "w"); if (fd) { fwrite(buffer, sizeof(char), strlen(buffer), fd); pclose(fd); exit(0); } return 0; } [lihui@localhost ~]# ./a.out 0000000 M y h e a r t w i l l g o 0000020 o n . . . 0000027