linux下代替system的基于管道的popen和pclose函数

简介: linux下使用system需要谨慎,那么代替它的方法是什么呢? 标准I/O函数库提供了popen函数,它启动另外一个进程去执行一个shell命令行。 这里我们称调用popen的进程为父进程,由popen启动的进程称为子进程。

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专栏

目录
相关文章
|
1月前
|
消息中间件 Linux
Linux中的System V通信标准--共享内存、消息队列以及信号量
希望本文能帮助您更好地理解和应用System V IPC机制,构建高效的Linux应用程序。
125 48
|
26天前
|
存储 Linux
linux中的目录操作函数
本文详细介绍了Linux系统编程中常用的目录操作函数,包括创建目录、删除目录、读取目录内容、遍历目录树以及获取和修改目录属性。这些函数是进行文件系统操作的基础,通过示例代码展示了其具体用法。希望本文能帮助您更好地理解和应用这些目录操作函数,提高系统编程的效率和能力。
111 26
|
3月前
|
Linux
【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解
System V信号量的概念及其在Linux中的使用,包括 `semget()`、`semctl()`和 `semop()`函数的具体使用方法。通过实际代码示例,演示了如何创建、初始化和使用信号量进行进程间同步。掌握这些知识,可以有效解决多进程编程中的同步问题,提高程序的可靠性和稳定性。
118 19
|
3月前
|
Linux Android开发 开发者
linux m、mm、mmm函数和make的区别
通过理解和合理使用这些命令,可以更高效地进行项目构建和管理,特别是在复杂的 Android 开发环境中。
93 18
|
3月前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
135 13
|
6月前
|
Docker 容器
14 response from daemon: open \\.\pipe\docker_engine_linux: The system cannot find the file speci
14 response from daemon: open \\.\pipe\docker_engine_linux: The system cannot find the file speci
111 1
|
6月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
266 6
|
7月前
|
Linux
Linux0.11 文件打开open函数(五)
Linux0.11 文件打开open函数(五)
86 0
|
10月前
|
Linux 开发者
Linux文件编程(open read write close函数)
通过这些函数,开发者可以在Linux环境下进行文件的读取、写入和管理。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
197 4
|
10月前
|
存储 Linux
Linux文件编程(open read write close函数)
Linux文件编程(open read write close函数)
293 0