天天看點

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,如需轉載請自行聯系原作者

繼續閱讀