标准I/O函数库提供了popen函数,它启动另外一个进程去执行一个shell命令行。
这里我们称调用popen的进程为父进程,由popen启动的进程称为子进程。
popen函数还创建一个管道用于父子进程间通信。子进程要么从管道读信息,要么向管道写信息,至于是读还是写取决于父进程调用popen时传递的参数。下在给出popen、pclose的定义:
view source
print?
01
#include <stdio.h>
02
09
FILE * popen( const char * command,const char * type);
10
11
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
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 来判断后才使用此宏。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)