当前位置: 首页 > news >正文

【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重伯努利试验 若是二项分布&#xff0c;则必是n重伯努利试验概型。即&#xff1a;每次试验只有两种结果 与 &#xff0c;且在每次试验中A发生的概率相等&#xff0c;即P(A)p&#xff0c;将这种试验独立重复n次&#xff0c;则称这种试验为n重伯努利试验&#…...

【飞控调试】DJIF450机架+Pixhawk6c mini+v1.13.3固件+好盈Platinium 40A电调无人机调试

1 背景 由于使用了一种新的航电设备组合&#xff0c;在调试无人机起飞的时候遇到了之前没有遇到的问题。之前用的飞控&#xff08;Pixhawk 6c&#xff09;和电调&#xff08;Hobbywing X-Rotor 40A&#xff09;&#xff0c;在QGC里按默认参数配置来基本就能平稳飞行&#xff0…...

Android studio配置Flutter开发环境报错问题解决

博主前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住也分享一下给大家 &#x1f449;点击跳转到教程 报错问题截图 报错原因已经给出&#xff1a; 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系统中&#xff0c;目录、字符设备、套接字、硬盘、光驱、打印机等都被抽象成文件形式&#xff0c;“Linux系统中一切都是文件”。Linux系统中的一切文件都是从"根"目录&#xff08;/&#xff09;开始的&#xff0c;并按照文件系统层次…...

深入理解网络协议:通信世界的基石

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在当今数字化时代&#xff0c;网络协议是连接世…...

PL/SQL编程

一、Oracle常用函数 concat&#xff1a;用于连接两个字符串。 CONCAT(Oraok, .com) -- Result: Oraok.com ceil&#xff1a;小数点向上取整。 secect ceil(7.3) from dual --Result: 8 dual表是oracle系统为计算设计的一张临时表 select sysdate as 系统日期 from dual…...

Prompt提示词——什么是CRISPE框架?QCIPSPE框架?

框架介绍 【CRISPE】框架 是由 Matt Nigh 提出并发布的提示词书写框架&#xff0c;共由五部分组成。 这个框架&#xff08;CRISPE&#xff09;主要包括五个部分&#xff0c;用于指导用户向ChatGPT提问。首先&#xff0c;通过设定ChatGPT的角色&#xff08;Capacity and Role&…...

Nginx的核心配置文件

Nginx的核心配置文件 学习Nginx首先需要对它的核心配置文件有一定的认识&#xff0c;这个文件位于Nginx的安装目录/usr/local/nginx/conf目录下&#xff0c;名字为nginx.conf 详细配置&#xff0c;可以参考resources目录下的<<nginx配置中文详解.conf>> Nginx的核…...

Java,集合框架,关于Collection接口(子接口List和Set)

目录 数组储存多个数据方面的特点&#xff1a; Java集合框架体系&#xff1a;&#xff08;Java.util包下&#xff09; Collection接口中的方法测试&#xff1a; 迭代器&#xff08;Iterator&#xff09;的作用&#xff1a;用来遍历集合元素。 增强for循环&#xff08;即for…...

已安装的nginx追加ssl模块

Nginx开启SSL模块1 切换到源码包&#xff1a; cd /usr/local/src/nginx-1.11.3 2 查看nginx原有的模块 /usr/local/nginx/sbin/nginx -V 在configure arguments:后面显示的原有的configure参数如下&#xff1a; –prefix/usr/local/nginx --with-http_stub_status_module …...

大语言模型|人工智能领域中备受关注的技术

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️其他领域】 文章目录 前言关于大语言模型大语言模型是什么&#xff1f;大语言模型有什么用?文案写作知识库回答文本分类代码生成 AWS 如何通过 LLM 提供帮助&#xff1f;Amazon BedrockAmazon SageM…...

Docker之DockerFile解析

DockerFile解析 是什么 Dockerfile是用来构建Docker镜像的文本文件&#xff0c;是由一条条构建镜像所需的指令和参数构成的脚本。 概述 官网 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 本地版本控制 本地版本控制系统 许多人习惯用复制整个项目目录的方式来保存不同的版本&#xff0c;或许还会改名加上备份时间以示区别。这么做唯一的 好处就是简单&#xff0c;但是特别容易犯错。有时候会混淆所在…...

iOS源码-工程目录讲解

1、 工程目录 1.1、xib 主要的界面渲染控制&#xff0c;ios开发常用的界面&#xff0c;可以在这里快速开发出来 1.2、base 基本的类&#xff0c;子类继承base类&#xff0c;就具备父类的方法&#xff0c;无需在重写 1.3、util 基础的类一些&#xff0c;处理时间等 1.4、…...

ESP32 Arduino实战协议篇-搭建独立的 Web 服务器

在此项目中,您将创建一个带有 ESP32 的独立 Web 服务器,该服务器使用 Arduino IDE 编程环境控制输出(两个 LED)。Web 服务器是移动响应的,可以使用本地网络上的任何浏览器设备进行访问。我们将向您展示如何创建 Web 服务器以及代码如何逐步工作。 项目概况 在直接进入项目…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;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 数据流…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在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&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;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 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...