【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 服务器以及代码如何逐步工作。 项目概况 在直接进入项目…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...

