Popen的使用方法

1.Popen的应用场景

popen应用于执行shell命令,并读取此命令的返值,或者与执行的命令进行交互。

2.Popen的实现

Popen()函数通过创建一个管道,调用fork()产生一个子进程,然后调用execl("/bin/sh", "sh", "-c”,command,0);执行shell命令。可以通过这个管道进行标准输入输出操作,下面会附上源码。

3.Pclose操作

Pclose()函数会闭标准i/0流,等待子进程结束,然后返回shell终止状态。如果不执行,则pclose()返回终止状态就是shell的exit状态。

源码附上:

/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>* Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>** Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.** Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.*//* Jan 1, 2004** Rewrite popen for SUSv3 compliance.*   Added a list of popen()'d to store pids and use waitpid() in pclose().*   Loop on waitpid() failure due to EINTR as required.*   Close parent's popen()'d FILEs in the {v}fork()'d child.*   Fix failure exit code for failed execve().*/#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <bits/uClibc_mutex.h>#ifdef __UCLIBC_MJN3_ONLY__
#warning "hmm... susv3 says Pipe streams are byte-oriented."
#endif /* __UCLIBC_MJN3_ONLY__ *//* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
#include <sys/syscall.h>
#if ! defined __NR_vfork
# define vfork fork
# define VFORK_LOCK     ((void) 0)
# define VFORK_UNLOCK       ((void) 0)
#endif#ifndef VFORK_LOCK
__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
# define VFORK_LOCK     __UCLIBC_MUTEX_LOCK(mylock)
# define VFORK_UNLOCK       __UCLIBC_MUTEX_UNLOCK(mylock)
#endifstruct popen_list_item {struct popen_list_item *next;FILE *f;pid_t pid;
};static struct popen_list_item *popen_list /* = NULL (bss initialized) */;FILE *popen(const char *command, const char *modes)
{FILE *fp;struct popen_list_item *pi;struct popen_list_item *po;int pipe_fd[2];int parent_fd;int child_fd;int child_writing;            /* Doubles as the desired child fildes. */pid_t pid;child_writing = 0;         /* Assume child is writing. */if (modes[0] != 'w') {     /* Parent not writing... */++child_writing;       /* so child must be writing. */if (modes[0] != 'r') {    /* Oops!  Parent not reading either! */__set_errno(EINVAL);goto RET_NULL;}}if (!(pi = malloc(sizeof(struct popen_list_item)))) {goto RET_NULL;}// 打开一个pipe,管道是单向。故数据流只能单向流动。if (pipe(pipe_fd)) {goto FREE_PI;}//下面两个描述符就是管道的两端的描述,一个为读一个为写。child_fd = pipe_fd[child_writing]; parent_fd = pipe_fd[1-child_writing]; //fdopen就是打开一个描述,fd相同模式或者字集的方式打开。意思就是把一个已找打开的流与一个文件描述符相关联,且//这个文件描述是唯一的,这样也就可以保证这个函数接口的可重入性。如果设计的不可重入性,也就没必要再做一次fdopen了。if (!(fp = fdopen(parent_fd, modes))) {close(parent_fd);close(child_fd);goto FREE_PI;}VFORK_LOCK;//再这里创建一个子进程,然后执行 shell命令。这里最重的两步就是用pipe的两个描述替换标准输入或者输出。if ((pid = vfork()) == 0) {    /* Child of vfork... */close(parent_fd);if (child_fd != child_writing) {dup2(child_fd, child_writing); //用child_fd来代替标准输入或输出。close(child_fd);}/* SUSv3 requires that any previously popen()'d streams in the* parent shall be closed in the child. *///关闭不必要的资源。for (po = popen_list ; po ; po = po->next) {close(po->f->__filedes);}//执行exec shell,这个时候标准输入/输出就变为pipe管道的一端了。//这里只能实现单向的功能。要么读要么写。execl("/bin/sh", "sh", "-c", command, (char *)0);/* SUSv3 mandates an exit code of 127 for the child if the* command interpreter can not be invoked. */_exit(127);}VFORK_UNLOCK;/* We need to close the child filedes whether vfork failed or* it succeeded and we're in the parent. */close(child_fd);//将当前的信息保存到全局链表。为了是pclose可以找到对的子进程与通信文件描述。if (pid > 0) {                /* Parent of vfork... */pi->pid = pid;pi->f = fp;VFORK_LOCK;pi->next = popen_list;popen_list = pi;VFORK_UNLOCK;return fp;}/* If we get here, vfork failed. */fclose(fp);                   /* Will close parent_fd. */FREE_PI:free(pi);RET_NULL:return NULL;
}#warning is pclose correct wrt the new mutex semantics?int pclose(FILE *stream)
{struct popen_list_item *p;int stat;pid_t pid;/* First, find the list entry corresponding to stream and remove it* from the list.  Set p to the list item (NULL if not found). */VFORK_LOCK;if ((p = popen_list) != NULL) {if (p->f == stream) {// 找到stream对应的popen结点。popen_list = p->next;} else {struct popen_list_item *t;do {t = p;if (!(p = t->next)) {__set_errno(EINVAL); /* Not required by SUSv3. */break;}if (p->f == stream) {t->next = p->next;break;}} while (1);}}VFORK_UNLOCK;if (p) {pid = p->pid;          /* Save the pid we need */free(p);              /* and free the list item. */fclose(stream);    /* The SUSv3 example code ignores the return. *//* SUSv3 specificly requires that pclose not return before the child* terminates, in order to disallow pclose from returning on EINTR. */do {if (waitpid(pid, &stat, 0) >= 0) { //等待子进程返回。获取返回值。return stat;}if (errno != EINTR) {break;}} while (1);}return -1;
}

举例附上:

#include <stdio.h>
#include <string.h>int main()
{FILE *fp = NULL;char buf[1024] = "";fp = popen("ls -al", "r");if(fp == NULL){perror("popen error\n");return -1;}while(fgets(buf, sizeof(buf), fp) != 0){printf("%s\n", buf);memset(buf, 0x0, sizeof(buf));}pclose(fp);return 0;
}

popen 的使用方法及场景相关推荐

  1. python私有方法应用场景_Python 私有属性和私有方法应用场景分析

    类的私有属性和方法 Python是个开放的语言,默认情况下所有的属性和方法都是公开的 或者叫公有方法,不像C++和 Java中有明确的public,private 关键字来区分私有公有. Python ...

  2. dnf命令参数详细说明、bclinux8或centos8以上系统使用dnf命令离线安装本地rpm包方法及场景和原因、使用dnf命令提示正在等待 pid 为422620的进程退出。的解决方法

    文章目录 dnf命令 dnf说明 安装 DNF 包管理器 dnf [选项] 命令 [dnf使用说明] dnf安装本地rpm包 全部参数 bclinux8或centos8以上系统使用dnf命令安装rpm ...

  3. popen使用方法及场景

    1. popen的应用场景 popen应用于执行shell命令,并读取此命令的返值,或者与执行的命令进行交互. 2. popen的实现 popen()函数通过创建一个管道,调用fork()产生一个子进 ...

  4. 【经验总结】C#常用线程同“.NET研究”步方法应用场景和实现原理

    简单描述volatile,Interlocked,lock,Mutex,Semaphore,Spin lock,AutoResetEvent,ManualResetEvent,ReaderWriter ...

  5. python私有方法应用场景_Python私有属性私有方法应用实例解析

    01. 应用场景及定义方式 应用场景 在实际开发中,对象 的 某些属性或方法 可能只希望 在对象的内部被使用,而 不希望在外部被访问到 私有属性 就是 对象 不希望公开的 属性 私有方法 就是 对象 ...

  6. Java私有方法运用场景_java6-3 封装和private关键字

    1.  private: 是一个权限修饰符 可以修饰成员变量和成员方法 被其修饰的成员只能在本类中被访问 定义一个学生类: 成员变量:name,age 成员方法:show()方法 2.我们在使用这个案 ...

  7. Java中注解与反射的使用方法及场景,强行解释一波!

    作者:BudingCode blog.csdn.net/m0_55221239/article/details/115025182 注解 注解定义 Java 注解(Annotation)又称 Java ...

  8. 软件测试—软件测试基础知识—测试用例设计的方法之场景法、正交试验法和错误推断法

    场景法 尽可能真实全部的模拟用户操作–订单,发货,商品状态变化 场景法主要基于: 1.业务(需求)层面 :对所测软件的重要功能.业务逻辑(系统要干什么,怎么去实现,这个过程).行业背景深入理解. 2. ...

  9. 商业模式新生代_商业模式设计方法之场景(化)——《商业模式新生代》之十二...

    今天我们来看#商业模式#设计方法的最后一种方法--场景,其实这里的场景不知道大家和我一样,看起来比较别扭,难以理解.因为这本书是舶来品,英译过来的,所以我只好用万能的百度来查了查,书里场景对应的单词是 ...

  10. SVN patch的使用方法及场景

    写目录 1. 客户端 1.1 相关功能菜单 1.1.1 `create patch` 1.1.2 `apply patch` 1.2 本次commit生成patch 1.3 多条commit合成pat ...

最新文章

  1. 体感(Kinect)开发要点总结一
  2. 11.MapReduce第1部分
  3. Webpack入门教程三
  4. DOM-1 DOM初探、JS对象、XML、幻灯片案例展示
  5. 区分大小屏幕_VESA持续推动DisplayHDR认证计划,你的屏幕属于何种等级吗?
  6. 反编译用unity打包的资源文件
  7. selinum-操作表单元素-0223
  8. SpringBoot 2.1.5(36)---整合Mybatis
  9. SQL优化:化解表关联的多对多join
  10. Mysql数据库安装和配置
  11. JS 判断是否为IP格式
  12. 解决全网 99的视频下载问题
  13. RL78平台开发注意点
  14. python excel怎么将字母后的数字取出来_利用通配符将Excel中英文字母、中文、数字提取出来...
  15. Springboot集成使用阿里云kafka详细步骤
  16. php手册中的tokenizer详细总结,基本看它就够了
  17. 多网聚合路由器全新面世,带来联网新体验
  18. 典型的NMOS开关驱动电路
  19. [电路笔记]非线性电路
  20. AliOS-Things开发入门

热门文章

  1. 什么是a站、b站、c站、d站、e站、f站、g站、h站、i站、j站、k站、l站、m站、n站…z站?
  2. Vue3 抽离封装axios
  3. 结巴分词--关键词抽取
  4. mysql不支持rank()_Mysql 实现 rank 和 != 问题
  5. 【考研英语语法】一般过去式练习题
  6. 计算机系统处理器好坏怎么看,台式电脑CPU怎么看好坏 CPU天梯图2019年2月最新版...
  7. 使用intel编译器编译WRF4.4
  8. 机器人设计必备的软件有哪些
  9. moneybookers api支付接口
  10. 解决大疆无人机飞了一段距离就停下来的问题(大疆限飞50米)