【Linux】进程替换|exec系列函数
文章目录
- 一、看一看单进程版的进程替换
- 二、进程替换的原理
- 三、多进程版——验证各种程序替换接口
- exec系列函数
- execl
- execlp
- execv
- execvp
- tips
- execle
- execve
- 四、总结
一、看一看单进程版的进程替换
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>int main()
{printf("before : I am a process, pid : %d,ppid : %d\n",getpid(),getppid());execl("/usr/bin/ls", "ls" , "-a" , "-l", NULL);printf("after : I am a process, pid : %d,ppid : %d\n",getpid(),getppid());return 0;
}

通过代码和现象可以看出,执行了execl函数之后,其之后的代码不再被执行。
而是执行了 ls -a -l 这条指令。
二、进程替换的原理

CPU首先执行父进程的代码,打印出before语句后,接下来执行execl系统调用。
ls -a -l也是一个文件,放在磁盘中,execl将ls -a -l文件的代码和数据进行替换,把调用execl系统调用的进程的数据和代码替换掉!
替换后,execl之后的代码不再被执行。
注意:进程替换仅仅是替换掉进程的数据和代码,并没有创建新的进程。所以进程的id没有改变
补充说明:
- 1.程序替换成功后,exec 系列的函数后面的代码不会被执行。
- 2.如果程序替换失败,才有可能执行后续的代码;并且,替换成功没有返回值,替换失败才有返回值。
三、多进程版——验证各种程序替换接口
exec系列函数

execl
int execl(const char *path, const char *arg, ...);
exec系列是进程替换的系统调用系列函数,l代表的就是list的意思。
就是链式的。
具体使用方法:
execl("/usr/bin/ls", "ls" , "-a" , "-l", NULL);
第一个参数就是执行的命令文件所在的路径。
第二个参数往后开始,就是要执行什么命令!
平常执行的命令是这样的:ls -a -l ,现在传参给execl后,只需要把空格变成逗号即可,并在最后加上一个NULL即可!
execl第一个参数要传路径的原因:
想要执行一个程序,就必须先找到这个程序!
execlp
int execlp(const char *file, const char *arg, ...);
p代表的就是PAHT环境变量。
代表的就是从自己的环境变量中查找路径。
所以,标准写法如下:
execlp("ls", "ls" , "-a" , "-l", NULL);
这样写,不带路径,执行该函数时系统会去环境变量中查找该命令所在路径。
当然,也可以这样写:
execlp("/usr/bin/ls", "ls" , "-a" , "-l", NULL);
这样写对编译器更好,也不用编译器自己去找了。
这里有个问题:
execlp("ls", "ls" , "-a" , "-l", NULL);
第一个ls和第二个ls一样吗?
答案是不一样的,前面说过,要执行一个程序,必须先找到该程序。
第一个ls其实就是程序所在的路径,只不过该函数可以通过PATH环境变量帮助我们找到ls这个命令。

也就是说通过环境变量和第一个ls,就能找到ls所在的路径:/usr/bin/ls
而第二个ls是我该怎么执行ls这个命令。
总结:第一个ls是找到ls这个命令在哪,第二个ls表示的是该怎么执行ls这个命令。
execv
这里的v就代表vector,也就是顺序表。
int execv(const char *path, char *const argv[]);
传递的第二个参数就由list变成了字符串指针数组。

核心的传参方式如下:
char* const argv[] = {"ls","-a","-l",NULL};
execv("/usr/bin/ls",argv);
第一个参数是路径,表示操作系统需要去哪个路径下执行命令,第二个参数是字符串指针数组。经过操作系统层面,会将数组的每一个字符串提取出来传递给第一个参数。
因为一个可执行程序肯定也有main函数,也就是说将argv作为参数传给了main函数,main函数就知道怎么执行该命令了。
execvp
与execlp类似,
int execvp(const char *file, char *const argv[]);
第一个参数传递的是文件路径,但是由于有环境变量的存在,使得CPU执行该系统调用时,不费什么劲就能找到file文件。
char* const argv[] = {"ls","-a","-l",NULL};
execvp("ls",argv);
第一个ls表明所需要执行的指令所在路径。
tips
注意:execl函数不仅能调用系统提供的函数,还能调用用户自己的命令,也就是还能通过execl函数调用其他可执行程序。
execl("./otherExe","otherExe",NULL);
因为不管是什么语言,都能夸语言调用!!!
因为无论是可执行程序还是脚本,本质都是进程!!!
是进程,都能进行进程进程替换,都能用exec系列函数调用!
所以可以通过该调用方法,来调用可执行程序。
验证execv可以将命令传递给其他可执行程序。
otherExe.c文件
int main(int argc,const char* argv[])
{int i = 0;for(;i<argc;i++){printf("%s\n",argv[i]);}return 0;
}test.c
int main()
{//多进程版进程替换char* const argv[] = {"ls","-a","-l",NULL};pid_t id = fork();if(id == 0){//childprintf("before : I am a child process, pid : %d,ppid : %d\n",getpid(),getppid());execvp("./otherExe",argv);printf("after : I am a child process, pid : %d,ppid : %d\n",getpid(),getppid());exit(0);}//father sleep(3);int status;pid_t ret = waitpid(id,&status,WNOHANG);if(ret == id){printf("wait success! wait pid is : %d \n",id);} return 0;
}

执行test可执行程序后,会将argv参数传递给otherExe可执行程序,然后打印出来。
总结:通过exec系列函数,可以调用其他的可执行程序。
问题2:进程替换时,环境变量会被替换吗?
答案是并不会。
当我们在test.c中调用otherExe.c时,并没有将环境变量传递给otherExe函数。

但是通过进程替换,仍然可以看到,otherExe函数仍然可以打印出环境变量!!!

otherExe.c文件如下:printf("这是命令行参数\n");
int i = 0;
for(;argv[i];i++)
{printf("%s\n",argv[i]);
}
printf("这是环境变量信息\n");i = 0;
for(;env[i];i++)
{printf("%s\n",env[i]);
}
结论:环境变量不会被进程替换给替换掉,进程替换只是替换进程的代码和数据。
环境变量会随着继承关系从父进程继承下来。
环境变量也是数据,创建子进程的时候就已经继承下来了。
在bash进程中导入环境变量:
export xxx=xxx;
bash中导入环境变量,同样会被子进程继承下来。
如果不想从bash中导入,而是从某一个进程中导入环境变量,则使用一个系统调用:putenv
int putenv(char *string);
哪个进程调用该函数,就向哪个进程中导入环境变量。
此后,所有该父进程的子进程都会继承该环境变量下来。
所以,从bash开始,只要导了环境变量,越往下,环境变量会越来越多。
execle
int execle(const char *path, const char *arg,..., char * const envp[]);
最后一个参数是环境变量数组,也就是当前进程的环境变量表。

在库的声明中,有一个environ变量,使用该变量也能将环境变量传给execle函数。
通过调用其他可执行程序,就能打印出环境变量了。
execve
int execve(const char *path, char *const argv[], char *const envp[]);
同样,只是比execv多了一个参数,该参数可以传environ,也就是把当前进程的环境变量传过去即可。
实际上,execve才是真正的系统调用,其他的exec*函数最终都是调用execve,所以execve在man手册的第二节,也就是系统调用那节,其他函数在man手册第三节。

四、总结
这篇文章重点讲解exec系列函数。
相关文章:
【Linux】进程替换|exec系列函数
文章目录 一、看一看单进程版的进程替换二、进程替换的原理三、多进程版——验证各种程序替换接口exec系列函数execlexeclpexecvexecvp tipsexecleexecve 四、总结 一、看一看单进程版的进程替换 #include<stdio.h> #include<unistd.h> #include<stdlib.h>i…...
Java编程技巧:将图片导出成pdf文件
目录 一、pom依赖二、代码三、测试链接 一、pom依赖 <!-- pdf插件 start --> <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.3</version> </dependency> <dependency…...
二项分布和泊松分布
一、二项分布 1.1 n重伯努利试验 若是二项分布,则必是n重伯努利试验概型。即:每次试验只有两种结果 与 ,且在每次试验中A发生的概率相等,即P(A)p,将这种试验独立重复n次,则称这种试验为n重伯努利试验&#…...
【飞控调试】DJIF450机架+Pixhawk6c mini+v1.13.3固件+好盈Platinium 40A电调无人机调试
1 背景 由于使用了一种新的航电设备组合,在调试无人机起飞的时候遇到了之前没有遇到的问题。之前用的飞控(Pixhawk 6c)和电调(Hobbywing X-Rotor 40A),在QGC里按默认参数配置来基本就能平稳飞行࿰…...
Android studio配置Flutter开发环境报错问题解决
博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家 👉点击跳转到教程 报错问题截图 报错原因已经给出: You need Java 11 or higher to build your app with this version of G…...
2023.11.18 -自用hadoop高可用环境搭建命令
启动hadoop高可用环境 # 1.先恢复快照到高可用环境 # 2.三台服务器启动zookeeper服务 [rootnode1 ~]# zkServer.sh start [rootnode2 ~]# zkServer.sh start [rootnode3 ~]# zkServer.sh start 查看服务状态: [rootnode]# zkServer.sh status 关闭zk服务的命令是: [rootnode]# …...
【Linux】常用系统工作命令
一、Linux文档目录结构 在Linux系统中,目录、字符设备、套接字、硬盘、光驱、打印机等都被抽象成文件形式,“Linux系统中一切都是文件”。Linux系统中的一切文件都是从"根"目录(/)开始的,并按照文件系统层次…...
深入理解网络协议:通信世界的基石
💂 个人网站:【 海拥】【神级代码资源网站】【办公神器】🤟 基于Web端打造的:👉轻量化工具创作平台💅 想寻找共同学习交流的小伙伴,请点击【全栈技术交流群】 在当今数字化时代,网络协议是连接世…...
PL/SQL编程
一、Oracle常用函数 concat:用于连接两个字符串。 CONCAT(Oraok, .com) -- Result: Oraok.com ceil:小数点向上取整。 secect ceil(7.3) from dual --Result: 8 dual表是oracle系统为计算设计的一张临时表 select sysdate as 系统日期 from dual…...
Prompt提示词——什么是CRISPE框架?QCIPSPE框架?
框架介绍 【CRISPE】框架 是由 Matt Nigh 提出并发布的提示词书写框架,共由五部分组成。 这个框架(CRISPE)主要包括五个部分,用于指导用户向ChatGPT提问。首先,通过设定ChatGPT的角色(Capacity and Role&…...
Nginx的核心配置文件
Nginx的核心配置文件 学习Nginx首先需要对它的核心配置文件有一定的认识,这个文件位于Nginx的安装目录/usr/local/nginx/conf目录下,名字为nginx.conf 详细配置,可以参考resources目录下的<<nginx配置中文详解.conf>> Nginx的核…...
Java,集合框架,关于Collection接口(子接口List和Set)
目录 数组储存多个数据方面的特点: Java集合框架体系:(Java.util包下) Collection接口中的方法测试: 迭代器(Iterator)的作用:用来遍历集合元素。 增强for循环(即for…...
已安装的nginx追加ssl模块
Nginx开启SSL模块1 切换到源码包: cd /usr/local/src/nginx-1.11.3 2 查看nginx原有的模块 /usr/local/nginx/sbin/nginx -V 在configure arguments:后面显示的原有的configure参数如下: –prefix/usr/local/nginx --with-http_stub_status_module …...
大语言模型|人工智能领域中备受关注的技术
个人主页:【😊个人主页】 系列专栏:【❤️其他领域】 文章目录 前言关于大语言模型大语言模型是什么?大语言模型有什么用?文案写作知识库回答文本分类代码生成 AWS 如何通过 LLM 提供帮助?Amazon BedrockAmazon SageM…...
Docker之DockerFile解析
DockerFile解析 是什么 Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。 概述 官网 https://docs.docker.com/engine/reference/builder/ 构建三步骤 编写Dockerfile文件 docker build命令构建镜像 docker run依镜像运…...
NSSCTF第13页(2)
[HNCTF 2022 Week1]Challenge__rce 提示?hint 访问看到了源码 <?php error_reporting(0); if (isset($_GET[hint])) { highlight_file(__FILE__); } if (isset($_POST[rce])) { $rce $_POST[rce]; if (strlen($rce) < 120) { if (is_string($rce…...
基于吉萨金字塔建造算法优化概率神经网络PNN的分类预测 - 附代码
基于吉萨金字塔建造算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于吉萨金字塔建造算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于吉萨金字塔建造优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&a…...
Git详解及 github使用
1.1 关于版本控制 开始之前先看一个没有版本控制的例子 1.1.1 本地版本控制 本地版本控制系统 许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别。这么做唯一的 好处就是简单,但是特别容易犯错。有时候会混淆所在…...
iOS源码-工程目录讲解
1、 工程目录 1.1、xib 主要的界面渲染控制,ios开发常用的界面,可以在这里快速开发出来 1.2、base 基本的类,子类继承base类,就具备父类的方法,无需在重写 1.3、util 基础的类一些,处理时间等 1.4、…...
ESP32 Arduino实战协议篇-搭建独立的 Web 服务器
在此项目中,您将创建一个带有 ESP32 的独立 Web 服务器,该服务器使用 Arduino IDE 编程环境控制输出(两个 LED)。Web 服务器是移动响应的,可以使用本地网络上的任何浏览器设备进行访问。我们将向您展示如何创建 Web 服务器以及代码如何逐步工作。 项目概况 在直接进入项目…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...

