linux下使用system需要谨慎,那么代替它的方法是什么呢?

标准I/O函数库提供了popen函数,它启动另外一个进程去执行一个shell命令行。

这里我们称调用popen的进程为父进程,由popen启动的进程称为子进程。

popen函数还创建一个管道用于父子进程间通信。父进程要么从管道读信息,要么向管道写信息,至于是读还是写取决于父进程调用popen时传递的参数。下在给出popen、pclose的定义:

01 #include <stdio.h>
02 /*
03 函数功能:popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。
04         参数type可使用“r”代表读取,“w”代表写入。
05         依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。
06         随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中
07 返回值:若成功则返回文件指针,否则返回NULL,错误原因存于errno中
08 */
09 FILE * popen( const char * command,const char * type);
10  
11 /*
12 函数功能:pclose()用来关闭由popen所建立的管道及文件指针。参数stream为先前由popen()所返回的文件指针
13 返回值:若成功返回shell的终止状态(也即子进程的终止状态),若出错返回-1,错误原因存于errno中
14 */
15 int pclose(FILE * stream);

下面通过例子看下popen的使用:

假如我们想取得当前目录下的文件个数,在shell下我们可以使用:

1 ls wc -l

我们可以在程序中这样写:

01 /*取得当前目录下的文件个数*/
02 #include <stdio.h>
03 #include <stdlib.h>
04 #include <errno.h>
05 #include <sys/wait.h>
06  
07 #define MAXLINE 1024
08  
09 int main()
10 {
11     char result_buf[MAXLINE], command[MAXLINE];
12     int rc = 0; // 用于接收命令返回值
13     FILE *fp;
14  
15     /*将要执行的命令写入buf*/
16     snprintf(command, sizeof(command), "ls ./ | wc -l");
17  
18     /*执行预先设定的命令,并读出该命令的标准输出*/
19     fp = popen(command, "r");
20     if(NULL == fp)
21     {
22         perror("popen执行失败!");
23         exit(1);
24     }
25     while(fgets(result_buf, sizeof(result_buf), fp) != NULL)
26     {
27         /*为了下面输出好看些,把命令返回的换行符去掉*/
28         if('\n' == result_buf[strlen(result_buf)-1])
29         {
30             result_buf[strlen(result_buf)-1] = '\0';
31         }
32         printf("命令【%s】 输出【%s】\r\n", command, result_buf);
33     }
34  
35     /*等待命令执行完毕并关闭管道及文件指针*/
36     rc = pclose(fp);
37     if(-1 == rc)
38     {
39         perror("关闭文件指针失败");
40         exit(1);
41     }
42     else
43     {
44         printf("命令【%s】子进程结束状态【%d】命令返回值【%d】\r\n", command, rc, WEXITSTATUS(rc));
45     }
46  
47     return 0;
48 }
编译并执行:

$ 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 来判断后才使用此宏。

更多内容请参考:shanzhizi专栏

linux下代替system的基于管道的popen和pclose函数的更多相关文章

  1. 【IPC通信】基于管道的popen和pclose函数

    http://my.oschina.net/renhc/blog/35116 [IPC通信]基于管道的popen和pclose函数 恋恋美食  恋恋美食 发布时间: 2011/11/12 23:20 ...

  2. [转][IPC通信]基于管道的popen和pclose函数

    标准I/O函数库提供了popen函数,它启动另外一个进程去执行一个shell命令行. 这里我们称调用popen的进程为父进程,由popen启动的进程称为子进程. popen函数还创建一个管道用于父子进 ...

  3. 【C/C++】Linux下使用system()函数一定要谨慎

    [C/C++]Linux下使用system()函数一定要谨慎 http://my.oschina.net/renhc/blog/53580 曾经的曾经,被system()函数折磨过,之所以这样,是因为 ...

  4. Linux进程间通信(三):匿名管道 popen()、pclose()、pipe()、close()、dup()、dup2()

    在前面,介绍了一种进程间的通信方式:使用信号,我们创建通知事件,并通过它引起响应,但传递的信息只是一个信号值.这里将介绍另一种进程间通信的方式——匿名管道,通过它进程间可以交换更多有用的数据. 一.什 ...

  5. [编译] 9、在Linux下搭建 nordic 最新基于 zephyr 的开发烧写环境

    目录 前言 1.概述 2.安装工具 3.获取 nRF Connect SDK 源码 4.安装 Python modules 5.安装 toolchain 6.下载 nRF Command Line T ...

  6. linux下安装svn(基于编码的方式)

    svn是什么,相信能看到这里的同学应该不会有这个问题了,费话不多说,开始: 1.创建目录 mkdir /home/svn/ 2.获取安装svn所需源文件(svn的官方网址是http://subvers ...

  7. [转载]Linux下关于system调用

    曾经的曾经,被system()函数折磨过,之所以这样,是因为对system()函数了解不够深入.只是简单的知道用这个函数执行一个系统命令,这远远不够,它的返回值.它所执行命令的返回值以及命令执行失败原 ...

  8. Linux下使用system()函数一定要谨慎

    转载自:http://my.oschina.net/renhc/blog/53580   linux尽量避免使用system. 曾经的曾经,被system()函数折磨过,之所以这样,是因为对syste ...

  9. Linux下的文件操作——基于文件描述符的文件操作(2)

    文件描述符的复制 MMAP文件映射 ftruncate修改文件大小 文件描述符的复制 ​ 系统调用函数dup和dup2可以实现文件描述符的复制,经常用来重定向进程的stdin(0), stdout(1 ...

随机推荐

  1. 【BZOJ-2648&2716】SJY摆棋子&天使玩偶 KD Tree

    2648: SJY摆棋子 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2459  Solved: 834[Submit][Status][Discu ...

  2. 【BZOJ-3555】企鹅QQ 字符串Hash

    3555: [Ctsc2014]企鹅QQ Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1545  Solved: 593[Submit][Statu ...

  3. 【poj2942】 Knights of the Round Table

    http://poj.org/problem?id=2942 (题目链接) 题意 有n个骑士要去参加圆桌会议,他们将围成一圈,想要他们不打架,当且仅当参加圆桌会议的骑士数为奇数并且相邻的两个骑士不互相 ...

  4. vijos2001 xor-sigma

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  5. BZOJ1040 [ZJOI2008]骑士

    Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各 界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战 ...

  6. Jenkins离线下载插件,并安装

     在jenkins点击插件进入wiki,然后点击列表下载一个版本的包 安装是,选择高级的tab,下面就有安装: 还有一种方法,就是装VPN,在高级设置VPN地址.

  7. asp.net接收ajax请求参数时为空的现象

    如题,如果使用ajax请求asp.net后台时,如果使用jquery时,默认是添加了请求头,使后台能识别,并能通过Request对象进行获取. 但是如果你使用的是window.XMLHttpReque ...

  8. C#把数据写到硬盘指定位置

    FileStream fs; StreamWriter sw;string RootPath = @"C:\Advantech" + "\\tempData\\" ...

  9. 第二次作业——C++学习

    课程选择: 以往在自学的过程就比较留意一些自学的网站,所以这次"C++自学"感觉找课程还是比较轻松的. 因为之前网页等学习都是在慕课网(视频学习个人感觉有时挺费时间的,特别是有时以 ...

  10. @interface NSFileManager : NSObject

    @interface NSFileManager : NSObject NSFileManager操作: 1.文件夹创建删除 2.文件创建删除 3.清除数据缓存 以上办法都在这里:https://de ...