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 () 。


目录
相关文章
|
1月前
|
消息中间件 Linux
Linux中的System V通信标准--共享内存、消息队列以及信号量
希望本文能帮助您更好地理解和应用System V IPC机制,构建高效的Linux应用程序。
126 48
|
1月前
|
Shell Linux
【linux】Shell脚本中basename和dirname的详细用法教程
本文详细介绍了Linux Shell脚本中 `basename`和 `dirname`命令的用法,包括去除路径信息、去除后缀、批量处理文件名和路径等。同时,通过文件备份和日志文件分离的实践应用,展示了这两个命令在实际脚本中的应用场景。希望本文能帮助您更好地理解和应用 `basename`和 `dirname`命令,提高Shell脚本编写的效率和灵活性。
101 32
|
2月前
|
监控 Linux
Linux systemd 服务启动失败Main process exited, code=exited, status=203/EXEC
通过以上步骤,可以有效解决 systemd 服务启动失败并报错 `Main process exited, code=exited, status=203/EXEC` 的问题。关键在于仔细检查单元文件配置、验证可执行文件的有效性,并通过日志分析具体错误原因。确保可执行文件路径正确、文件具有执行权限,并且可以独立运行,将有助于快速定位和解决问题。
810 7
|
3月前
|
Linux
【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解
System V信号量的概念及其在Linux中的使用,包括 `semget()`、`semctl()`和 `semop()`函数的具体使用方法。通过实际代码示例,演示了如何创建、初始化和使用信号量进行进程间同步。掌握这些知识,可以有效解决多进程编程中的同步问题,提高程序的可靠性和稳定性。
130 19
|
4月前
|
存储 Shell Linux
Linux 如何更改默认 Shell
Linux 如何更改默认 Shell
146 0
Linux 如何更改默认 Shell
|
5月前
|
Web App开发 网络协议 Linux
linux命令总结(centos):shell常用命令汇总,平时用不到,用到就懵逼忘了,于是专门写了这篇论文,【便持续更新】
这篇文章是关于Linux命令的总结,涵盖了从基础操作到网络配置等多个方面的命令及其使用方法。
133 1
linux命令总结(centos):shell常用命令汇总,平时用不到,用到就懵逼忘了,于是专门写了这篇论文,【便持续更新】
|
4月前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
5月前
|
Shell Linux C语言
Shell 函数
10月更文挑战第4天
42 7
|
5月前
|
消息中间件 存储 Linux
Linux手账—exec和fork
本文介绍了Linux系统中进程控制的核心功能——`fork`和`exec`系列函数。`fork`用于创建新进程(子进程),继承父进程的资源但拥有独立的地址空间;`exec`系列函数则在当前进程中执行新程序,替换原有地址空间。文章详细解析了这些函数的基本概念、用法及工作原理,强调了它们在多进程编程中的重要性。
91 0
|
5月前
|
Shell Docker 容器
使用exec模式与shell模式,执行ENTRYPOINT和CMD的区别
结合 `exec`与 `shell`模式,`ENTRYPOINT`与 `CMD`在Docker容器启动时的交互方式展现出不同的特点。选择哪种模式,取决于对执行环境的纯净度、性能需求以及是否需要利用shell特性。理解这些细微差别,有助于更精细地控制容器的行为,优化应用部署与管理流程。
176 0