目录
本文经作者授权转载,
原文链接:https://zhuanlan.zhihu.com/p/457974696
前文深入探讨了system()函数的用法和注意事项,作为它的兄弟函数popen()有什么特殊之处?为什么很多网友和技术大佬都推荐使用它替代system()来使用呢?这就是本文要探讨的内容。
一、基本功能和测试
1.头文件包含
#include <stdio.h>
2.函数原型
3.测试代码
(1)测试目的
测试代码实现对popen执行命令和读/写命令结果的测试。
(2)测试结果分析
测试结果:
(.1)执行ls,并读取它的stdout,打印出来。结果可见,父进程拿到了ls的标准输出,并打印出来了。
(.2)执行./test,并向它的stdin写入字符串。结果可见,./test子进程收到了父进程给他标准输入写入
的字符串。
(3)测试源码
首先我们要写一个测试程序,用来被popen启动,并接收来自popen调用者的标准输入。
这个程序就是:test.c ,编译得到test。
#include <stdio.h>
#include <string.h>
/*
*打印stdin的输入
*用来测试popen的写入功能
*打印来自popen的写入
**/
int main(int argc,char **argv)
{
char buf[256];
memset(buf,0,sizeof(buf));
printf("pls intput:");
scanf("%s",buf);
printf("Your input is %s\n",buf);
return 0;
}
然后我们再写一个调用popen函数的测试程序wpopen.c,编译得到wpopen,wpopen具有的功能是以'r'或'w'模式调用popen打开另一个应用程序,如果是'r'则从应用程序的标准输出读出内容并打印,如果是'w'则把argv[3]的内容传给应用程序。
/*
*Copyright (c) 2021 hwtech/X_XCoder.
*All rights reserved.
*作者:hwtech/X_XCoder
*微信号:X_XCoder
*博客:https://blog.csdn.net/u013752202
*知乎:https://www.zhihu.com/people/xiao-yuan-50-93-23
*开源协议:
*版权声明:
* 版权归属hwtech/X_XCoder,您可以下载所有源码学习使用,但不能用于商业用途。
*如需在个人项目中使用,需保留该版权声明。作者拥有所有代码版权,及解释权如有建
*议,可以联系作者。
*
******************宏伟精讲-popen使用演示*****************
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
int main(int argc,char **argv)
{
int ret=0;
char buf[256];
if(argc<3){
printf("Usages: %s cmd r/w\n",argv[0]);
return -1;
}
FILE *pfp=popen(argv[1],argv[2]);
if(!pfp){
printf("popen %s error,errno=%d\n",argv[1],errno);
return 0;
}
printf("\n********宏伟精讲-popen使用演示********\n");
//如果参数2是w,就把参数参传给子进程的stdin
if('w'==argv[2][0]){
fprintf(pfp,"%s\n",argv[3]);
}
memset(buf,0,sizeof(buf));
while(fgets(buf,sizeof(buf),pfp)){
printf("%s",buf);
memset(buf,0,sizeof(buf));
}
ret=pclose(pfp);
printf("pclose ret =%d\n",ret);
//返回值处理
if(1==ret){
printf("程序命令为空\n");
}
else if(-1==ret){
printf("创建命令子进程失败\n");
}
else if(0x7f00==ret){
printf("命令错误,无法执行\n");
}
else{
if(WIFEXITED(ret)){
printf("程序正常结束,返回值:%d\n",WEXITSTATUS(ret));
}
else if(WIFSIGNALED(ret)){
printf("程序被信号杀死,信号值:%d\n",WTERMSIG(ret));
}
else if(WSTOPSIG(ret)){
printf("程序被信号暂停,信号值:%d\n",WSTOPSIG(ret));
}
}
printf("**************************\n\n");
return 0;
}
二、与system()比较
关于system()详见《linux-api-system研究》一文。
通过文中介绍,我们知道system()函数不仅返回值五花八门,对信号处理也不太好理解。那么popen是否有同样的问题呢?
1.阻塞进程
(1)是否跟system()一样?
答案:不一样。
(2)详述
前面的测试结果可见,popen调用到pclose调用之间的程序没有被阻塞,pclose后面的代码被阻塞了。所以popen不会阻塞调用者进程,但是pclose会阻塞,也就是说popen-pclose把system调用分开了,以便用户在popen后可以继续运行主进程。
2.返回值
(1)是否跟system()一样?
答案:不一样。
(2)详述
popen返回值很简单,要么非NULL,要么NULL。但是要注意,popen返回成功只代表管道创建成功,不能说明命令执行成功,命令执行结果需要通过pclose返回值来判断。
pclose返回值就跟system除开-1,1后一样。也不简单。
3.SIGCHLD
(1)是否跟system()一样?
答案:一样。
(2)详述
system()命令执行的时候会阻塞主进程的SIGCHLD,调用system()之前如果执行signal(SIGCHLD,SIG_IGN),会导致system返回-1,但命令执行成功的情况。
popen会不会呢?
实际测试发现,如果在pclose之前加了signal(SIGCHLD,SIG_IGN),那么pclose也会跟system()一样,无法通过返回值判断命令执行状态。所以SIGCHLD信号处理跟system是一样的。
4.SIGINT和SIGQUIT
(1)是否跟system()一样?
答案:不一样。
(2)详述
system()命令执行的时候,主进程无法收到SIGINT和SIGQUIT。
popen会不会呢?
下面测试结果表明,popen执行命令的过程中,主进程可以正常响应SIGINT和SIGQUIT。这点跟system()不一样。
三、相关文章
之前一直埋头搞开发,最近开始输出博文,文章观点经实践验证,但仍不能保证百分之百无误,如有建议,欢迎留言指出,一定虚心受教,及时修改。如有疑问,欢迎留言咨询,知无不言。
但求精品,不问数量。博文会持续输出,但更新速度可能较慢,还往海涵。
后续博文,敬请关注,……