Linux中执行Shell的函数(popen,system,exec)介绍:分享一些常用的执行Shell的函数及其相关编程技巧和经验

概要

Linux下的C编程有以下几种方法可以执行shell命令:

  • popen()函数
  • system()函数
  • exec函数簇

popen(建立管道I/O)

函数原型

 FILE *popen(const char cmd,const char type);
//若成功返回文件指针,出错则返回NULL。 

参数:

  • cmd
    是一个指向以NULL结束的shell命令字符串的指针。这行命令将被传到bin/sh并使用-c标志,shell将执行这个命令。
    可以通过这个管道执行标准输入输出操作,这个管道必须由pclose()函数关闭,而不是fclose()函数(若使用fclose则会产生僵尸进程)。
    pclose()函数关闭标准I/O流,等待命令执行结束,然后返回shell的终止状态。
    如果shell不能被执行,则pclose()返回的终止状态与shell已执行exit一样。

  • type
    只能是读或者写中的一种,得到的返回值(标准I/O流)也具有和type相应的只读或只写类型。
    如果type=r,那么该管道的方向为:子进程的stdout到父进程的FILE指针,即连接到cmd的标准输出;
    如果type=w,那么管道的方向为:父进程的FILE指针到子进程的stdin,即连接到cmd的标准输入。

返回值:
如果调用fork()或pipe()失败,或者不能分配内存将返回NULL,否则返回标准I/O流。 popen()没有为内存分配失败设置errno值。
如果调用fork()或pipe()时出现错误,errno被设为相应的错误类型。
如果type参数不合法,errno将返回EINVAL


流程:

  1. 创建一个匿名管道
  2. 调用fork()或者invoke()产生一个子进程
  3. 接着关闭管道的不使用端
  4. 子进程执行cmd指向的应用程序或者命令
  5. 执行完该函数后父进程和子进程之间生成一条管道
  6. 函数返回值为FILE结构指针,该指针作为管道的一端,为父进程所拥有.**

子进程则拥有管道的另一端,该端口为子进程的stdin或者stdout。
这个流是单向的(只能用于读或写),向这个流写内容相当于写入该命令的标准输入,命令的标准输出和调用popen()的进程相同,
与之相反的,从流中读数据相当于读取命令的标准输出,命令的标准输入和调用popen()的进程相同。


system(执行shell 命令)

system()通过调用/bin/sh -c命令执行command中指定的命令,并在命令完成后返回。
在执行命令期间,SIGCHLD将被阻塞,SIGINTSIGQUIT将被忽略<意思是进程收到这两个信号后没有任何动作>。


函数原型

#include <stdlib.h> 
int system(const char *command);
//返回是否成功.

返回值:
如果出现错误(例如fork(2) failed),返回的值为-1,否则返回命令的状态
后一种返回状态采用wait(2)中指定的格式.因此,命令的退出代码将是WEXITSTATUS(status)。

  • 如果/bin/sh无法执行,则退出状态将是exit(127)的命令的退出状态。
  • 如果command的值为NULL,那么system()在shell可用时返回非零,如果shell不可用则返回零。

源码实现:

int system(const char * cmdstring) {
    pid_t pid;
    int status;
    if(cmdstring == NULL) {
        return (1); //如果cmdstring为空,返回非零值,一般为1
    }
    if((pid = fork())<0) {
        status = -1; //fork失败,返回-1
    } else if (pid == 0) {
        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
        _exit(127); // exec执行失败返回127,注意exec只在失败时才返回现在的进程,成功的话现在的进程就不存在
    } else { //父进程
        while(waitpid(pid, &status, 0) < 0) {
            if(errno != EINTR) {
                status = -1; //如果waitpid被信号中断,则返回-1
                break;
            }
        }
    }
    return status; //如果waitpid成功,则返回子进程的返回状态 }

popen()与system()之间的区别

执行过程

  • popen相当于是先创建一个管道fork关闭管道的一端,执行exec,返回一个标准的io文件指针.

  • system相当于是先后调用了fork, exec,wait来执行外部命令.


阻塞关系

  • popen本身是不阻塞的,要通过标准io的读取使它阻塞
    不会等待子进程的结束并杀死子进程,即不会管理进程。

  • system本身就是阻塞的。
    会自动对进程进行管理,无需我们再去对进程进行管理。


返回值

  • popen会将执行的结果返回到buf中。

  • system不会返回执行的结果,只是会返回执行是否成功


功能

  • popen () 可以控制进程的输入或输出文件流。

  • system () 没有,如果不需要访问进程的I / O,则可以使用 system () 。


exec函数簇

linux 系统编程之exec函数簇的使用


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泡沫o0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值