【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 的简单介绍到这里就结束了,欢迎评论区交流
- 最新
- 最热
- 最早
- 作者
点击重新获取 | 打开控制台