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

简介: 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 () 。


目录
相关文章
|
5天前
|
Shell Linux 程序员
【Linux】Shell 命令以及运行原理
【Linux】Shell 命令以及运行原理
|
6天前
|
Shell Linux
【linux课设】自主实现shell命令行解释器
【linux课设】自主实现shell命令行解释器
|
6天前
|
存储 Unix Linux
linux权限管理以及shell
linux权限管理以及shell
|
7天前
|
运维 Linux Shell
day02-Linux运维-系统介绍与环境搭建_硬件 系统核心 解释器shell 外围操作系统
day02-Linux运维-系统介绍与环境搭建_硬件 系统核心 解释器shell 外围操作系统
|
13天前
|
Shell Linux Perl
Linux|如何允许 awk 使用 Shell 变量
Linux|如何允许 awk 使用 Shell 变量
22 2
|
13天前
|
网络协议 Shell Linux
LabVIEW 在NI Linux实时设备上访问Shell
LabVIEW 在NI Linux实时设备上访问Shell
17 0
|
13天前
|
消息中间件 算法 Linux
【Linux】对system V本地通信的内核级理解
【Linux】对system V本地通信的内核级理解
|
13天前
|
Shell Linux
【Linux】进程实践项目(更新中) — 自主shell编写
前几篇文章,我们学习进程的相关知识:进程概念,进程替换,进程控制。熟悉了进程到底是个什么事情,接下来我们来做一个实践,来运用我们所学的相关知识。这个项目就是手搓一个shell模块,模拟实现Xshell中的命令行输入。
16 1
|
2天前
|
存储 Linux 网络安全
在 Linux 中通过 SSH 执行远程命令时,无法自动加载环境变量(已解决)
SSH远程执行命令时遇到“命令未找到”问题,原因是Linux登录方式不同导致环境变量加载差异。解决方案:将环境变量写入`/etc/profile.d/`下的文件,或手动在命令前加载环境变量,如`source /etc/profile`。
|
3天前
|
关系型数据库 MySQL Java
1.Linux常用命令
1.Linux常用命令
14 1