【Linux】popen pclose接口介绍
本篇文章简单讲述了c语言接口popen/pclose
的用法
1.函数作用
函数定义如下
1 |
|
popen函数会创建一个管道,fork一个子进程,关闭管道的不使用端,通过exec函数执行一个shell命令,等待命令终止。并将命令的输出结果通过管道返回给当前的进程;
1.1 popen
popen函数会创建一个管道,fork后调用shell来打开进程。由于管道的定义是单向的,第二个参数type只能指定读或写,不能同时指定读和写;
所得到的管道相应地是只读或只写的
The popen() function opens a process by creating a pipe, forking, and invoking the shell. Since a pipe is by definition unidirectional, the type argument may specify only reading or writing, not both; the resulting stream is correspondingly read-only or write-only.
简单说来,popen会自动帮我们fork创建子进程和一个管道,将我们传入的参数command
在shell中执行后,将返回值以管道文件的形式发送给调用方。
如果调用fork或pipe
失败,或者不能分配内存,将返回NULL;否则返回标准I/O流。popen()
没有为内存分配失败设置errno值。如果调用fork()或pipe()时出现错误,errno被设为相应的错误类型。如果type参数不合法,errno将返回EINVAL
1.2 pclose
这个函数没有什么好说的,是用来关掉popen打开的文件的(即popen的返回值)
但是,它的返回值可有说到了,其返回值就是我们终端操作的退出状态,以标识命令是否成功执行
但是这个返回是通过wait4
得到的,如果wait4
出现错误,就会返回-1并设置errno
1 | The pclose() function returns -1 if wait4(2) returns an error, or some other error is detected. In the event of an error, these functions set errnro to indicate the cause of the error. |
这里还出现了一个新的错误码errnro
,但是经过我的一番百度,没有发现任何地方有对errnro的说明,man手册下方又变成了errno
1 | If pclose() cannot obtain the child status, errno is set to ECHILD. |
而且编译执行的时候,errnro
是会报错的,所以姑且认为这里是man手册出错了!
errno
才是正确的
1 | int ret = pclose(f); |
2.代码示例
2.1 popen读
以下方最简单的ls命令为例,我们以读方式打开,popen就会将ls的执行结果写到文件里面返回给我们
1 |
|
编译后执行结果如下
1 | $ ./test |
2.2 popen写
和读不同,如果用写方式执行popen,命令的输出结果会直接打印到屏幕上
1 | void test2(FILE* f) |
1 | makefile test test.cpp |
这里我还以为后续可以接着往管道里面写数据,让他继续执行命令
1 | void test2(FILE* f) |
可测试的结果告诉我,并不行
1 | cmd: ls -l |
网上的资料大多数都是只演示了r方法,我不确定这里是不是我写的代码有问题,还是说本来就是这样的。暂且停留在这里吧!
3.优缺点
优点是:由于所有类Unix系统中参数扩展都是由shell完成的,所有它运行我们通过popen完成非常复杂的shell命令。而其他一些创建进程的函数(如execl)调用起来就复杂的多,因为调用进程必须自己完成shell扩展。
缺点是:针对每个popen调用,不仅要启动一个被请求的程序,还要启动一个shell,即每个popen调用将启动两个进程。从节省系统资源的角度来看,popen函数的调用成本略高,并且对目标命令的调用比正常方式慢一些(通过pipe改进)。
end
关于popen和pclose的简单介绍到这里就结束了,欢迎评论区交流