Chinaunix首页 | 论坛 | 博客
  • 博客访问: 306214
  • 博文数量: 65
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 284
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-21 15:10
文章分类
文章存档

2016年(3)

2015年(51)

2014年(8)

2013年(3)

分类: LINUX

2015-04-28 15:24:56

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

阅读(2856) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~