【Linux】进程控制之进程程序替换

目录

前言

替换的原理

替换函数

记忆技巧

函数使用

execl

execlp

execv

execvp 

execle

execvpe 

调用其它语言的程序

模拟实现一个shell


前言

关于本文可以先去看看上一篇【Linux】进程控制详解-CSDN博客可以更好的理解这里的内容

学完本篇文章,你就可以自己设计一个mini版的shell解释器,还可以用你写自己的代码区执行其它语言的程序。

替换的原理

用fork创建子进程后执行的是和父进程相同的代码,但有可能需要执行不同的代码分支,那么子进程往往要调用一种exec系列函数以执行另一个全新程序。当进程调用一种exec系列函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec系列函数并不创建新进程,所以调用exec系列函数前后该进程的ID并未改变。

替换函数

返回值:如果调用成功则加载新的程序从启动代码开始执行,不在返回;调用失败则返回-1。

记忆技巧

  • l(list):表示参数采用列表
  • v(vector):表示参数采用数组
  • p(path):第一个参数path不用输入路径,给出命令名即可,它会在环境变量PATH当中搜索对应的命令
  • e(env):将自己维护的环境变量传递给需要替换的进程
函数名参数格式是否带路径是否使用当前环境变量
execl列表
execlp列表
execle列表否,需自己维护环境变量
execv数组
execvp数组
execvpe数组否,需自己维护环境变量

函数使用

一旦发生了替换,那么替换函数后面的代码就不会再执行了。

int main()
{printf("当前进程的开始代码\n");execl("/usr/bin/ls", "ls", "-a", "-l", NULL);printf("当前进程的结束代码\n");return 0:
}

 

注:在调用替换函数时末尾最好加上NULL代表结束。

虽然我们可以不用创建子进程来使用替换函数,但是我们创建了子进程,替换的进程就是子进程而父进程不受影响,那么父进程就可以聚焦在读取数据,解析数据,指派进程执行代码等功能了。 

execl

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{pid_t id = fork();if(id < 0){perror("fork");exit(2);//子进程创建失败}else if(id == 0){//子进程printf("子进程开始执行,pid:%d\n", getpid());execl("/usr/bin/ls", "ls", "-a", "-l", NULL);exit(1);//替换失败则终止进程}else {//父进程printf("父进程开始执行,pid:%d\n", getpid());int status;pid_t wid = waitpid(-1, &status, 0);//阻塞等待if(wid > 0){printf("wait success, exit code:%d\n", WEXITSTATUS(status));}}return 0;
}

 

execlp

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{pid_t id = fork();if(id < 0){perror("fork");exit(2);//子进程创建失败}else if(id == 0){//子进程printf("子进程开始执行,pid:%d\n", getpid());execlp("ls", "ls", "-a", "-l", NULL);exit(1);//替换失败则终止进程}else {//父进程printf("父进程开始执行,pid:%d\n", getpid());int status;pid_t wid = waitpid(-1, &status, 0);//阻塞等待if(wid > 0){printf("wait success, exit code:%d\n", WEXITSTATUS(status));}}return 0;
}

execv

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>#define NUM 16int main()
{pid_t id = fork();if(id < 0){perror("fork");exit(2);//子进程创建失败}else if(id == 0){//子进程printf("子进程开始执行,pid:%d\n", getpid());char* const _argv[NUM] = {(char*)"ls",(char*)"-a",(char*)"-l",NULL };execv("/usr/bin/ls", _argv);exit(1);//替换失败则终止进程}else {//父进程printf("父进程开始执行,pid:%d\n", getpid());int status;pid_t wid = waitpid(-1, &status, 0);//阻塞等待if(wid > 0){printf("wait success, exit code:%d\n", WEXITSTATUS(status));}}return 0;
}

execvp 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>#define NUM 16int main()
{pid_t id = fork();if(id < 0){perror("fork");exit(2);//子进程创建失败}else if(id == 0){//子进程printf("子进程开始执行,pid:%d\n", getpid());//execl("/usr/bin/ls", "ls", "-a", "-l", NULL);//execlp("ls", "ls", "-a", "-l", NULL);char* const _argv[NUM] = {(char*)"ls",(char*)"-a",(char*)"-l",NULL };execvp("ls", _argv);exit(1);//替换失败则终止进程}else {//父进程printf("父进程开始执行,pid:%d\n", getpid());int status;pid_t wid = waitpid(-1, &status, 0);//阻塞等待if(wid > 0){printf("wait success, exit code:%d\n", WEXITSTATUS(status));}}return 0;
}

execle

 mycmd.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char* argv[])
{if(argc != 2){printf("can not execute\n");exit(1);}printf("获取环境变量:MY_VALUE:%s\n", getenv("MA_VALUE"));if(strcmp(argv[1], "-a") == 0){printf("hello 我是a\n");}else if(strcmp(argv[1], "-b") == 0){printf("hello 我是b\n");}else {printf("defalut\n");}return 0;
}

myproc.c 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>#define NUM 16
const char* myfile = "/home/hjx/for_linuxtest/test43/mycmd";int main(int argc, char* argv[], char* env[])
{char* const _env[NUM] = {(char*)"MY_VALUE=332335454",NULL };pid_t id = fork();if(id < 0){perror("fork");exit(2);//子进程创建失败}else if(id == 0){//子进程printf("子进程开始执行,pid:%d\n", getpid());execle(myfile, "mycmd", "-a", NULL, _env);exit(1);//替换失败则终止进程}else {//父进程printf("父进程开始执行,pid:%d\n", getpid());int status;pid_t wid = waitpid(-1, &status, 0);//阻塞等待if(wid > 0){printf("wait success, exit code:%d\n", WEXITSTATUS(status));}}return 0;
}

 

所以mycmd.c就拿到了这里的环境变量

execvpe 

和上面的类似就不再演示了

 其实系统调用的接口只有一个——execve

而以上介绍的函数是操作系统是为了满足不同的调用场景提供的基本封装。

调用其它语言的程序

print("hello python")
print("hello python")
print("hello python")
print("hello python")
print("hello python")
print("hello python")
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{pid_t id = fork();if(id < 0){perror("fork");exit(2);//子进程创建失败}else if(id == 0){//子进程printf("子进程开始执行,pid:%d\n", getpid());execlp("python", "python", "test.py", NULL);exit(1);//替换失败则终止进程}else {//父进程printf("父进程开始执行,pid:%d\n", getpid());int status;pid_t wid = waitpid(-1, &status, 0);//阻塞等待if(wid > 0){printf("wait success, exit code:%d\n", WEXITSTATUS(status));}}return 0;
}

模拟实现一个shell

有了上面的这些知识,那么我们可以自己设计一个简易版的shell。

shell代码链接:minishell

效果展示


今天的分享就到这里了,如果内容有错的话,还望指出,谢谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/794596.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅聊什么是Redis?

需求&#xff1a;MySQL面临大量的查询&#xff0c;即读写操作&#xff0c;因此类比CPU&#xff0c;给数据加缓存&#xff0c;Redis诞生。应用程序从MySQL查询的数据&#xff0c;在Redis设置缓存&#xff08;记录在内存中&#xff0c;无需IO操作&#xff09;&#xff0c;后再需要…

【吊打面试官系列】Redis篇 - 使用过 Redis 分布式锁么,它是什么回事?

大家好&#xff0c;我是锋哥。今天分享关于 【使用过 Redis 分布式锁么&#xff0c;它是什么回事&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 使用过 Redis 分布式锁么&#xff0c;它是什么回事&#xff1f; 先拿 setnx 来争抢锁&#xff0c;抢到之后&#…

2.Swift基础控件:图标文字按钮

Swift图标标题按钮 一、自定义IconTitleButton类 import Foundation/* 枚举 设置 图片的位置 */ enum ButtonImagePosition : Int {case imageTop 0case imageLeftcase imageBottomcase imageRight } extension UIButton {/**type &#xff1a;image 的位置Space &#xff1…

leetcode代码记录(买卖股票的最佳时机

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股…

蓝桥-时间显示

目录 题目链接 代码 题目链接 1.时间显示 - 蓝桥云课 (lanqiao.cn) 代码 #include <bits/stdc.h> using namespace std;int main() {long long x;cin>>x;int h,m,s;x x / 1000 % (3600*24); // 毫秒化秒&#xff0c;并且保留最后一天的时间h x / 3600; //求得…

第四百四十三回

文章目录 1. 概念介绍2. 思路与方法2.1 整体思路2.2 使用方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"自定义Action菜单"相关的内容&#xff0c;本章回中将介绍如何获取屏幕相关参数.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…

Qtxlsx第三方库的安装和使用

本文仅作为一个记录&#xff0c;安装QtXlsx方便操作excel&#xff0c;主要参考了这篇博文&#xff1a;https://blog.csdn.net/u014779536/article/details/111769792 1&#xff0c;下载安装Perl脚本Strawberry Perl for Windows&#xff0c;默认安装strawberry-perl-5.30.0.1-…

程序·人生

诡异之极 2024.03.12 清新环境&#xff08;股票代码002573&#xff09;委托卖出 20000股&#xff0c;委托价4.58&#xff0c;当日最高价4.57 2024.03.11 清新环境&#xff08;股票代码002573&#xff09;委托卖出 20000股&#xff0c;委托价4.55&#xff0c;当日最高价4.54 …

汉明码检错与纠错的结论(hamming code)

假如一组二进制数据为101&#xff0c;另外一组为111&#xff0c;那么显然把第一组的第二位数据0改成1就可以变成第二组数据111&#xff0c;所以两组数据的汉明距离就为1 简单点说&#xff0c;汉明距离就是一组二进制数据变成另一组数据所需的步骤数&#xff08;它表示两个相同长…

策略模式图

策略模式 小小的图解 主要的三个角色 Strategy—抽象策略角色ConcreateStrategy—具体策略角色Context—上下文角色 封装了对具体策略的调用可以使用set的依赖注入也可以使用构造方法 核心是上下文角色 只要调用上下文角色就行&#xff0c;实现解耦 策略 工厂 将上下文角…

深入理解MP4视频文件裁剪原理[下下]

深入理解MP4视频文件裁剪原理[上] 深入理解MP4视频文件裁剪原理[中] 深入理解MP4视频文件裁剪原理[下] 深入理解MP4视频文件裁剪原理[下下] 3.22 stco box* stco box记录了每个chunk在MP4文件中的偏移量。如下图24: 图24 这里的offset指的是chunk的起始位置相对于整个MP4文…

Pytoch安装记录

使用pycharm 1、CUDA的安装 官网&#xff1a;CUDA Toolkit Archive | NVIDIA Developer 选择对应的版本 选择对应的版本进行下载&#xff1a; 有3个多G cuda的安装需要注意&#xff0c;如果没有安装vs&#xff0c;则需要选择自定义安装&#xff0c;在自定义的安装中取消 安…

【系统架构师】-系统可靠性分析与设计

1、可靠性与可用性区别 1、系统可靠性&#xff1a;系统在规定时间内及规定的环境下&#xff0c;完成规定功能的能力&#xff0c;即系统无故障运行的概率 2、系统可用性&#xff1a;在某个给定时间点上系统能够按照需求执行的概率。 可靠性分为软件、硬件可靠性 2、可靠性指标…

观察者模式 C++

&#x1f442; Honey Honey - 孙燕姿 - 单曲 - 网易云音乐 目录 &#x1f33c;前言 &#x1f33c;描述 &#x1f382;问题 &#x1f4aa;解决方案 &#x1f232;现实场景 代码 场景1 -- 报纸发行 场景 解释 代码 场景2 -- 气象资料发布 场景3 -- 过红绿灯 &#x…

视频分块上传Vue3+SpringBoot3+Minio

文章目录 一、简化演示分块上传、合并分块断点续传秒传 二、更详细的逻辑和细节问题可能存在的隐患 三、代码示例前端代码后端代码 一、简化演示 分块上传、合并分块 前端将完整的视频文件分割成多份文件块&#xff0c;依次上传到后端&#xff0c;后端将其保存到文件系统。前…

C++读取.bin二进制文件

C读取.bin二进制文件 在C中&#xff0c;可以使用文件输入/输出流来进行二进制文件的读写操作&#xff0c;方便数据的保存和读写。 //C读取bin二进制文件 int read_bin() {std::ifstream file("data_100.bin", std::ios::in | std::ios::binary);if (file) {// 按照…

【拓扑空间】示例及详解1

例1 度量空间的任意两球形邻域的交集是若干球形邻域的并集 Proof&#xff1a; 任取空间的两个球形邻域、&#xff0c;令 任取,令 球形领域 例2 规定X的子集族,证明是X上的一个拓扑 Proof&#xff1a; 1. 2., &#xff08;若干个球形邻域的并集都是的元素&#xff0c;元素…

SSM 项目学习(Vue3+ElementPlus+Axios+SSM)

文章目录 1 项目介绍1.1 项目功能/界面 2 项目基础环境搭建2.1 创建项目2.2 项目全局配置 web.xml2.3 SpringMVC 配置2.4 配置 Spring 和 MyBatis , 并完成整合2.5 创建表&#xff0c;使用逆向工程生成 Bean、XxxMapper 和 XxxMapper.xml2.6 注意事项和细节说明 3 实现功能 01-…

Java 开发者必备:JDK 版本详解与选择策略(含安装与验证)

1. JDK 版本 (Oracle Java SE 支持路线图) 数据来源&#xff1a;Oracle Java SE 支持路线图 | 甲骨文中国: https://www.oracle.com/cn/java/technologies/java-se-support-roadmap.html 版本GA DatePremier Support UntilExtended Support Until&#xff08;限 LTS&#xff09…

虚幻UE5数字孪生蓝图开发教程

一、背景 这几年&#xff0c;智慧城市/智慧交通/智慧水利等飞速发展&#xff0c;骑士特意为大家做了一个这块的学习路线。 二、这是学习大纲 1.给虚幻UE5初学者准备的智慧城市/数字孪生蓝图开发教程 https://www.bilibili.com/video/BV1894y1u78G 2.UE5数字孪生蓝图开发教学…