天天看点

popen 函数

函数原型:

#include<stdio.h>

FILE*   popen(const  char*  command,    const   char*  type);

void  pclose(FILE*  stream);

man文本英语描述:

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.

      The  command argument is a pointer to a null-terminated string contain‐

       ing 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  contain

       either the letter 'r' for reading or the letter 'w' for writing.  Since

       glibc 2.9, this argument can additionally include the letter 'e', which

       causes  the close-on-exec flag (FD_CLOEXEC) to be set on the underlying

       file descriptor; see the description of the O_CLOEXEC flag  in  open(2)

       for reasons why this may be useful.

RETURN VALUE:

       The popen() function returns NULL if the fork(2) or pipe(2) calls fail,

       or if it cannot allocate memory.

       The pclose() function returns -1 if wait4(2) returns an error, or  some

       other error is detected.  In the event of an error, these functions set

       errno to indicate the cause of the error.

ERRORS:

       The popen() function does not set errno if memory allocation fails.  If

       the  underlying  fork(2)  or pipe(2) fails, errno is set appropriately.

       If the type argument is invalid, and this condition is detected,  errno

       is set to EINVAL.

       If pclose() cannot obtain the child status, errno is set to ECHILD.

中文总结:

popen函数是通过创建一个管道的方式打开一个进程,并调用shell。因为管道是被定义为单向的,所以type的值只能是r或w其中的一个,结果流也是如此。

command(命令行/命令的意思)参数:是一个以NULL结尾的字符串,这个字符串应是一个shell命令。这个命令会被送到 /bin/sh中,并以 -c执行即被shell执行。

type参数:只能是r或w中的一个,r或w是相当command管道而言的。r表示从command管道中读,w表示通过command管道输出到stdout中(输出流为全缓冲)。

返回值:如果fork或者pipe失败,或者不能分配到内存都会返回NULL,成功则返回标志I/O流。popen没有为申请内存失败设置errno值,但fork和pipe都有其相应的errno值。如果type参数不合法,errno会别设置为EINVAL.

注意:只能用pclose函数进行关闭操作,不能用fclose。

相关代码:

type为  r时:

#include<unistd.h>

#include<stdlib.h>

#include<sys/types.h>

#include<string.h>

const int BUF_SIZE = 1024;

int main()

{

    FILE* stream;

    FILE* wstream;

    char buf[BUF_SIZE];

    stream = popen("ls -l","r");

    wstream = fopen("test_popen.txt","w+");

    memset(buf, '\0', sizeof(buf));

    fread(buf, sizeof(char), sizeof(buf), stream);//把返回标准I/O流内的内容读到buf中

    fwrite(buf,sizeof(char), strlen(buf), wstream);

    fclose(wstream);//一定要记得关闭

    pclose(stream);//只能用pclose不能用fclose

    return 0;

}

执行结果:

<a href="http://s1.51cto.com/wyfs02/M02/7E/ED/wKiom1cM25WiarsQAABpPzqeJMM765.png" target="_blank"></a>

当type为 w  时:(此时popen函数会通过FIFO管道直接向stdout中写数据)

    stream = popen("ls -l","w");

    if(stream == NULL)

    {

        perror("popen");

        return -1;

    }

    pclose(stream);

<a href="http://s1.51cto.com/wyfs02/M01/7E/EA/wKioL1cM3t3SYSpqAABKBRBo5j8839.png" target="_blank"></a>

注意:一个执行的命令是 cat  test_popen.txt        一个是./a.out

以下是在网上找到的popen函数和pclose函数实现的代码:

Figure 15.12. The popen and pclose functions  

#include "apue.h"  

#include &lt;errno.h&gt;  

#include &lt;fcntl.h&gt;  

#include &lt;sys/wait.h&gt;  

/* 

 * Pointer to array allocated at run-time. 

 */  

static pid_t    *childpid = NULL;  

 * From our open_max(), Figure 2.16. 

static int      maxfd;  

FILE *  

popen(const char *cmdstring, const char *type)  

{  

    int     i;  

    int     pfd[2];  

    pid_t   pid;  

    FILE    *fp;  

    /* only allow "r" or "w" */  

    if ((type[0] != 'r' &amp;&amp; type[0] != 'w') || type[1] != 0) {  

        errno = EINVAL;     /* required by POSIX */  

        return(NULL);  

    }  

    if (childpid == NULL) {     /* first time through */  

        /* allocate zeroed out array for child pids */  

        maxfd = open_max();  

        if ((childpid = calloc(maxfd, sizeof(pid_t))) == NULL)  

            return(NULL);  

    if (pipe(pfd) &lt; 0)  

        return(NULL);   /* errno set by pipe() */  

    if ((pid = fork()) &lt; 0) {  

        return(NULL);   /* errno set by fork() */  

    } else if (pid == 0) {                           /* child */  

        if (*type == 'r') {  

            close(pfd[0]);  

            if (pfd[1] != STDOUT_FILENO) {  

                dup2(pfd[1], STDOUT_FILENO);  

                close(pfd[1]);  

            }  

        } else {  

            close(pfd[1]);  

            if (pfd[0] != STDIN_FILENO) {  

                dup2(pfd[0], STDIN_FILENO);  

                close(pfd[0]);  

        }  

        /* close all descriptors in childpid[] */  

        for (i = 0; i &lt; maxfd; i++)  

            if (childpid[i] &gt; 0)  

                close(i);  

        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);  

        _exit(127);  

    /* parent continues... */  

    if (*type == 'r') {  

        close(pfd[1]);  

        if ((fp = fdopen(pfd[0], type)) == NULL)  

    } else {  

        close(pfd[0]);  

        if ((fp = fdopen(pfd[1], type)) == NULL)  

    childpid[fileno(fp)] = pid; /* remember child pid for this fd */  

    return(fp);  

}  

int  

pclose(FILE *fp)  

    int     fd, stat;  

    if (childpid == NULL) {  

        errno = EINVAL;  

        return(-1);     /* popen() has never been called */  

    fd = fileno(fp);  

    if ((pid = childpid[fd]) == 0) {  

        return(-1);     /* fp wasn't opened by popen() */  

    childpid[fd] = 0;  

    if (fclose(fp) == EOF)  

        return(-1);  

    while (waitpid(pid, &amp;stat, 0) &lt; 0)  

        if (errno != EINTR)  

            return(-1); /* error other than EINTR from waitpid() */  

    return(stat);   /* return child's termination status */  

本文转自 ye小灰灰  51CTO博客,原文链接:http://blog.51cto.com/10704527/1763143,如需转载请自行联系原作者

继续阅读