[转][IPC通信]基于管道的popen和pclose函数
标准I/O函数库提供了popen函数,它启动另外一个进程去执行一个shell命令行。
这里我们称调用popen的进程为父进程,由popen启动的进程称为子进程。
popen函数还创建一个管道用于父子进程间通信。父进程要么从管道读信息,要么向管道写信息,至于是读还是写取决于父进程调用popen时传递的参数。下在给出popen、pclose的定义:
#include <stdio.h>
/*
函数功能:popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。
参数type可使用“r”代表读取,“w”代表写入。
依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。
随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中
返回值:若成功则返回文件指针,否则返回NULL,错误原因存于errno中
*/
FILE * popen( const char * command,const char * type); /*
函数功能:pclose()用来关闭由popen所建立的管道及文件指针。参数stream为先前由popen()所返回的文件指针
返回值:若成功返回shell的终止状态(也即子进程的终止状态),若出错返回-1,错误原因存于errno中
*/
int pclose(FILE * stream);
下面通过例子看下popen的使用:
假如我们想取得当前目录下的文件个数,在shell下我们可以使用:
ls | wc -l
/*取得当前目录下的文件个数*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h> #define MAXLINE 1024 int main()
{
char result_buf[MAXLINE], command[MAXLINE];
int rc = 0; // 用于接收命令返回值
FILE *fp; /*将要执行的命令写入buf*/
snprintf(command, sizeof(command), "ls ./ | wc -l"); /*执行预先设定的命令,并读出该命令的标准输出*/
fp = popen(command, "r");
if(NULL == fp)
{
perror("popen执行失败!");
exit(1);
}
while(fgets(result_buf, sizeof(result_buf), fp) != NULL)
{
/*为了下面输出好看些,把命令返回的换行符去掉*/
if('\n' == result_buf[strlen(result_buf)-1])
{
result_buf[strlen(result_buf)-1] = '\0';
}
printf("命令【%s】 输出【%s】\r\n", command, result_buf);
} /*等待命令执行完毕并关闭管道及文件指针*/
rc = pclose(fp);
if(-1 == rc)
{
perror("关闭文件指针失败");
exit(1);
}
else
{
printf("命令【%s】子进程结束状态【%d】命令返回值【%d】\r\n", command, rc, WEXITSTATUS(rc));
} return 0;
}
$ gcc popen.c
$ ./a.out
命令【ls ./ | wc -l】 输出【2】
命令【ls ./ | wc -l】子进程结束状态【0】命令返回值【0】
上面popen只捕获了command的标准输出,如果command执行失败,子进程会把错误信息打印到标准错误输出,父进程就无法获取。比如,command命令为“ls nofile.txt” ,事实上我们根本没有nofile.txt这个文件,这时shell会输出“ls: nofile.txt: No such file or directory”。这个输出是在标准错误输出上的。通过上面的程序并无法获取。
注:如果你把上面程序中的command设成“ls nofile.txt”,编译执行程序你会看到如下结果:
$ gcc popen.c
$ ./a.out
ls: nofile.txt: No such file or directory
命令【ls nofile.txt】子进程结束状态【256】命令返回值【1】
需要注意的是第一行输出并不是父进程的输出,而是子进程的标准错误输出。
有时子进程的错误信息是很有用的,那么父进程怎么才能获取子进程的错误信息呢?
这里我们可以重定向子进程的错误输出,让错误输出重定向到标准输出(2>&1),这样父进程就可以捕获子进程的错误信息了。例如command为“ls nofile.txt 2>&1”,输出如下:
命令【ls nofile.txt 2>&1】 输出【ls: nofile.txt: No such file or directory】
命令【ls nofile.txt 2>&1】子进程结束状态【256】命令返回值【1】
附:子进程的终止状态判断涉及到的宏,设进程终止状态为status.
WIFEXITED(status)如果子进程正常结束则为非0值。
WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。
WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真。
WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏。
WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。
WSTOPSIG(status)取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED 来判断后才使用此宏。
[转][IPC通信]基于管道的popen和pclose函数的更多相关文章
- 【IPC通信】基于管道的popen和pclose函数
http://my.oschina.net/renhc/blog/35116 [IPC通信]基于管道的popen和pclose函数 恋恋美食 恋恋美食 发布时间: 2011/11/12 23:20 ...
- linux下代替system的基于管道的popen和pclose函数
linux下使用system需要谨慎,那么代替它的方法是什么呢? 标准I/O函数库提供了popen函数,它启动另外一个进程去执行一个shell命令行. 这里我们称调用popen的进程为父进程,由pop ...
- 进程间通信之popen和pclose函数
常见的操作是创建一个管道连接到另一个进程,然后读其输出或向其输入端发送数据,为此,标准I/O库提供了两个函数popen和pclose.这两个函数实现的操作是:创建一个管道,调用fork产生一个子进程, ...
- Android Binder机制详解:手写IPC通信
想要掌握一样东西,最好的方式就是阅读理解它的源码.想要掌握Android Binder,最好的方式就是写一个AIDL文件,然后查看其生成的代码.本文的思路也是来自于此. 简介 Binder是Andro ...
- Binder机制,从Java到C (9. IPC通信过程)
1.一次IPC通信過程的幾個步驟 一次通信过程简单的说有下面5个步骤,第一眼看上去,肯定不知道什么玩意,多看几遍,慢慢看,其实是能理解的. 1. Client将数据封装成Parcel. (前面已经讲过 ...
- IPC通信:Posix消息队列
IPC通信:Posix消息队列 消息队列可以认为是一个链表.进程(线程)可以往里写消息,也可以从里面取出消息.一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息. ...
- linux进程篇 (三) 进程间的通信3 IPC通信
3 IPC通信 用户空间 进程A <----无法通信----> 进程B -----------------|--------------------------------------|- ...
- android IPC通信(上)-sharedUserId&&Messenger
看了一本书,上面有一章解说了IPC(Inter-Process Communication,进程间通信)通信.决定结合曾经的一篇博客android 两个应用之间的通信与调用和自己的理解来好好整理总结一 ...
- python 之 并发编程(守护进程、互斥锁、IPC通信机制)
9.5 守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就立即终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic process ...
随机推荐
- noip模拟赛 剪纸
题目描述 小芳有一张n*m的长方形纸片.每次小芳将会从这个纸片里面剪去一个最大的正方形纸片,直到全部剪完(剩下一个正方形)为止. 小芳总共能得到多少片正方形纸片? 输入输出格式 输入格式: 一行两个整 ...
- 互联网DSP广告系统架构及关键技术解析
互联网DSP广告系统架构及关键技术解析 宿逆 关注 1.9 2017.10.09 17:05* 字数 8206 阅读 10271评论 2喜欢 60 广告和网络游戏是互联网企业主要的盈利模式 广告是广告 ...
- ZOJ——3609 Modular Inverse
Modular Inverse Time Limit: 2 Seconds Memory Limit: 65536 KB The modular modular multiplicative ...
- vue2的简单Popup (Confirm,Alert)组件
github: https://github.com/longfei59418888/vui (记得给一个 start,以后有一起讨论,各种好组件) demo :http://60.205.20 ...
- 解决canvas跨域问题(图片,视频资源跨域)
添加跨域条件 crossorigin="anonymous" [Redirect at origin 'http://xxx.xx.com' has been blocked ...
- PayPal加密证书.pem的生成
How do I create a public certificate for use with PayPal Encrypted Website Payments? Before you ca ...
- 在全程Linux環境部署IBM Lotus Domino/Notes 8.5
架設藍色巨人的協同合作訊息平台 在全程Linux環境部署IBM Lotus Domino/Notes 8.5 珊迪小姐 坊間幾乎所有探討IBM Domino/Notes的中文書籍,皆是以部署在Micr ...
- MVC中从控制器到视图的数据传递方法汇总
1.ViewData对象概述ViewData是一种字典集合数据,是"视图基类"和"控制器基类"的属性常见用法是在控制器中写入数据,在视图中读取数据ViewDat ...
- [Vue-rx] Handle Image Loading Errors in Vue.js with RxJS and domStreams
When an image fails to load, it triggers an error event. You can capture the error event and merge i ...
- ios学习之旅---指针也不难
1.认识指针 #include <stdio.h> //基本数据类型作为函数參数传递是值传递 //void moveFront(int x ,int y) //{ // x = x + 2 ...