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.


中文总结:

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

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

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

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

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


相关代码:

type为  r时:

#include<stdio.h>
#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;
}

执行结果:

wKiom1cM25WiarsQAABpPzqeJMM765.png


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

#include<stdio.h>

int main()
{
    FILE* stream;
    stream = popen("ls -l","w");
    if(stream == NULL)
    {
        perror("popen");
        return -1;
    }
    pclose(stream);
    return 0;
}


wKioL1cM3t3SYSpqAABKBRBo5j8839.png

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




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

Figure 15.12. The popen and pclose functions  

#include "apue.h"  

#include <errno.h>  

#include <fcntl.h>  

#include <sys/wait.h>  

  

/* 

 * 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' && 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) < 0)  

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

  

    if ((pid = fork()) < 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 < maxfd; i++)  

            if (childpid[i] > 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)  

            return(NULL);  

    } else {  

        close(pfd[0]);  

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

            return(NULL);  

    }  

  

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

    return(fp);  

}  

  

  

int  

pclose(FILE *fp)  

{  

    int     fd, stat;  

    pid_t   pid;  

  

    if (childpid == NULL) {  

        errno = EINVAL;  

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

    }  

  

    fd = fileno(fp);  

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

        errno = EINVAL;  

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

    }  

  

    childpid[fd] = 0;  

    if (fclose(fp) == EOF)  

        return(-1);  

  

    while (waitpid(pid, &stat, 0) < 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,如需转载请自行联系原作者
目录
相关文章
|
Unix Shell API
subprocess模块
subprocess模块
71 0
|
2月前
|
Shell Python
python中的subprocess.Popen | 9
python中的subprocess.Popen | 9
|
2月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
95 6
|
物联网 Linux C语言
Execve 函数|学习笔记
快速学习 Execve 函数
Execve 函数|学习笔记
|
物联网 Linux C语言
Execl 函数|学习笔记
快速学习 Execl 函数
Execl 函数|学习笔记
|
Ubuntu
stat()函数、fstat()函数和lstat()函数
stat()函数、fstat()函数和lstat()函数
155 0
|
Python
Python 技术篇-通过管道命令获取cmd执行的结果,获取os.system()、subprocess.Popen()执行命令返回的结果
Python 技术篇-通过管道命令获取cmd执行的结果,获取os.system()、subprocess.Popen()执行命令返回的结果
704 0
Python 技术篇-通过管道命令获取cmd执行的结果,获取os.system()、subprocess.Popen()执行命令返回的结果
|
Linux Shell
详解linux进程间通信-管道 popen函数 dup2函数
  前言:进程之间交换信息的唯一方法是经由f o r k或e x e c传送打开文件,或通过文件系统。本章将说明进程之间相互通信的其他技术—I P C(InterProcess Communication)。
1587 0
|
Python