进程管道popen

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

发表回复