分类: LINUX
2015-04-23 14:59:23
popen函数还创建一个管道用于父子进程间通信。父进程要么从管道读信息,要么向管道写信息,至于是读还是写取决于父进程调用popen时传递的参数。
POPEN(3) Linux Programmer’s Manual POPEN(3)
NAME
popen, pclose - process I/O
//popen, pclose – 进程I/O
SYNOPSIS
#include
//包含头文件
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
DESCRIPTION
The popen() function opens a process by creating a pipe,
forking, and invoking the shell. Since a pipe is by definition
unidirectional, the type argument may specify only reading
or writing, not both; the resulting stream is correspondingly
read-only or write-only.
//popen()函数通过创造管道、forking、调用shell打开进程,
自定义单向管道,type参数可以指定只能读或写,并不是两个
都有;导致产生的流是只读或者只写
The command argument is a pointer to a null-terminated string
containing a shell command line. This command is passed to
/bin/sh using the -c flag; interpretation, if any, is performed
by the shell. The type argument is a pointer to a
null-terminated string which must be either ‘r’ for reading
or ‘w’ for writing.
//compemand参数是一个以null结尾的字符串指针包含shell命令行。
command通过/bin/sh使用—c标志;如果有的话,是通过shell完
成的。type参数是一个以null结尾的字符串指针必须那么是“r”读
要么是“w”写。
The return value from popen() is a normal standard I/O stream
in all respects save that it must be closed with pclose()
rather than fclose(). Writing to such a stream writes to the
standard input of the command; the command’s standard output
is the same as that of the process that called popen(),
unless this is altered by the command itself. Conversely,
reading from a ‘‘popened’’ stream reads the command’s
standard output, and the command’s standard input is
the same as that of the process that called popen().
// popen()的返回值是一个在各方面保存的正常的标准I / O流,
它必须关pclose()而不是fclose()。写这样一个流写入标准输
入的命令; 命令的标准输出是同样的进程称为popen(),除非
这是命令本身的改变。读从一个“popened”流读取命令的标
准输出,和命令的标准输入相同的进程称为popen()。
Note that output popen() streams are fully buffered by
default.
//注意,输出popen()流完全默认缓冲。
The pclose() function waits for the associated process to
terminate and returns the exit status of the command as
returned by wait4().
//pclose()函数等待相关进程终止,返回命令的退出状态作为wait4()
的返回
RETURN VALUE
The popen() function returns NULL if the fork(2) or pipe(2)
calls fail, or if it cannot allocate memory.
//如果fork(2)或者pipe(2)调用失败,或者如果它不能分配内存,
popen()函数返回空。
The pclose() function returns -1 if wait4() returns an error,
or some other error is detected.
//如果wait4()返回到errno中或者有其他的错误被检测,pclose()
函数返回-1.
ERRORS
The popen() function does not set errno if memory allocation
fails. If the underlying fork() or pipe() fails, errno is
set appropriately. If the type argument is invalid, and this
condition is detected, errno is set to EINVAL.
//如果分配内存失败,popen()函数不设置errno。如果底层的
fork()或者pipe()失败,errno适当地设置。如果type参数是
无效的,这种情况呗检测到,errno设置成EINVAL。
If pclose() cannot obtain the child status, errno is set to
ECHILD.
//如果pclose()不能获得子状态,errno就设置成ECHILD。
CONFORMING TO
POSIX.1-2001. BUGS
Since the standard input of a command opened for reading
shares its seek offset with the process that called popen(),
if the original process has done a buffered read, the com-
mand’s input position may not be as expected. Similarly, the
output from a command opened for writing may become intermin-
gled with that of the original process. The latter can be
avoided by calling fflush(3) before popen().
Failure to execute the shell is indistinguishable from the
shell’s failure to execute command, or an immediate exit of
the command. The only hint is an exit status of 127.
HISTORY
A popen() and a pclose() function appeared in Version 7 AT&T
UNIX.
SEE ALSO
sh(1), fork(2), pipe(2), wait4(2), fclose(3), fflush(3),
fopen(3), stdio(3), system(3)
BSD MANPAGE 1998-05-07 POPEN(3)
(END)
for example
/*取得当前目录下的文件个数*/ |
||
#include |
#include |
||
#include |
#include |
||
|
#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 来判断后才使用此宏。