【Linux系统】进程替换 自主实现shell(简易版)

1.先看代码 && 现象

 我们用exec*函数执行新的程序,

exec*系列的函数,执行完毕后,后续的代码不见了,因为被替换了。

execl的返回值可以不关心了,只要替换成功,就不会向后继续运行,只要继续运行了,一定是替换失败了!

2.解释原理

 进程 = 内核数据结构 + 代码数据

进程的程序替换,有没有创建新的进程?? 没有的

站在被替换进程的角度:本质就是这个程序被加载到内存了!

怎么加载?exec*类似于Linux上的加载函数

3.将代码改成多进程版

fork创建子进程,让子进程自己去替换,wait等待

创建子进程,让子进程完成任务:

  1. 让子进程执行父进程代码的一部分
  2. 让子进程执行一个全新的程序

4.使用所有的替换方法,并且认识函数参数的含义

下面我们查的是这些替换方法,用man 3 execl

3手册是c语言的标准库GNU标准,所以我们实际查的是几个内含系统调用的c语言函数。

 

 这是6个exec*系列函数。

 第一个execl函数:

path:我们要执行的程序,需要带路径(怎么找到程序你得告诉我)

exec后面的l -- list:就是要存放的选项列表,在命令行中怎么执行,你就怎么传参!ls -a -l 

execl("/usr/bin/ls", "ls", "-a", "-l", NULL);

路径代表你想执行谁,选项代表你想怎么执行!!!

带l的是我们要传入一个列表选项,那么带v的呢?

 v:有动态数组的意思。

 明显是要我们传入一个数组,这个数组就包含我们想要的选项,

 带p的exec函数:

用户可以不传要执行的文件的路径(但是文件名要传),直接告诉exec*,我要执行谁就行

p:查找这个程序,系统会自动在环境变量PATH中进行查找。

 

 e:environment环境变量。

envp[]:整体替换所有的环境变量!

  1. 用全新的给子进程。
  2. 用老的环境变量给子进程,environ。
  3. 老的环境变量稍微修改,给子进程。

上面的程序替换 ,我们替换的都是系统命令,可不可以替换我们自己写的程序呢?

支持不同的应用场景!!!

当然可以。 而且可以替换用任何语言写的无论是c++,java,python等语言都可进行替换,替换之后原程序pid不会改变,创建的子进程也不会改变,因为进程的替换,只是代码和数据的替换,不影响原程序的pcb。

系统调用接口execve。

 上面的函数最终都将会走到系统调用接口。

5.写一个自己的Shell(简易版)

#include<stdio.h>    
#include<stdlib.h>    
#include<string.h>    
#include<ctype.h>    
#include<unistd.h>    
#include<errno.h>    
#include<sys/types.h>    
#include<sys/wait.h>    #define SIZE 512    
#define ZERO '\0'    
#define SEP " "    
#define NUM 32    
#define SkipPath(p) do{p += (strlen(p)-1);while(*p != '/')--p;}while(0)    char cwd[SIZE * 2];    
char* gArgv[NUM];    
int lastcode = 0;    void Die()    
{    exit(1);    
}    
const char* GetHome()    
{    const char* home = getenv("HOME");                                                                                                                                                   if(home == NULL) return "None";    return home;    
}    
const char* GetUserName()
{    const char* username = getenv("USER");if(username == NULL) return "None";return username;
}const char* GetHostName()
{const char* hostname = getenv("HOSTNAME");if(hostname == NULL) return "None";return hostname;
}const char* GetCwd()
{const char* cwd = getenv("PWD");if(cwd == NULL) return "None";return cwd;
}
//commandline:output
void MakeCommandLineAndPrint()
{char line[SIZE];const char* username = GetUserName();const char* hostname = GetHostName();const char* cwd = GetCwd();const char* GetCwd()
{const char* cwd = getenv("PWD");if(cwd == NULL) return "None";return cwd;                                                                                                                                                                          
}
//commandline:output
void MakeCommandLineAndPrint()
{char line[SIZE];const char* username = GetUserName();const char* hostname = GetHostName();const char* cwd = GetCwd();SkipPath(cwd);snprintf(line, sizeof(line), "[%s@%s %s]>", username, hostname, strlen(cwd) == 1 ? "/" : cwd + 1);printf("%s", line);fflush(stdout);
}
int GetUserCommand(char command[], size_t n)
{char* s = fgets(command, n, stdin);if(s == NULL) return -1;command[strlen(command) - 1] = ZERO;return strlen(command);
}
void SplitCommand(char command[], size_t n)
{(void)n;//"ls -a -l" ->  "ls", "-a", "-l"gArgv[0] = strtok(command, SEP);int index = 1;                                                                                                                                                                       while((gArgv[index] = strtok(NULL, SEP)))index++;// done, 故意写成=,表示先赋值,在判断,分割之后,strtok会返回NULL,刚好让gArgv最后一个元素是NULL,并且while判断结束
}void ExecuteCommand()
{pid_t id = fork();if(id < 0) Die();else if(id == 0){//childexecvp(gArgv[0], gArgv);exit(errno);}else {//fatherint status = 0;pid_t rid = waitpid(id, &status, 0);if(rid > 0){lastcode = WEXITSTATUS(status);if(lastcode != 0) printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode);}}
}
void Cd()
{const char* path = gArgv[1];if(path == NULL) path = GetHome();//path一定存在chdir(path);//刷新环境变量char temp[SIZE * 2];getcwd(temp, sizeof(temp));snprintf(cwd, sizeof(cwd), "PWD=%s", temp);putenv(cwd);//ok
}
int CheckBuildin()
{int yes = 0;const char* enter_cmd = gArgv[0];if(strcmp(enter_cmd, "cd") == 0){yes = 1;Cd();}else if(strcmp(enter_cmd, "echo") == 0 && strcmp(gArgv[1], "$?") == 0){yes = 1;printf("%d\n", lastcode);lastcode = 0;}return yes;
}
int main()
{int quit = 0;while(!quit)                                                                                                                                                                         {//1.我们需要输出一个命令行MakeCommandLineAndPrint();//2.获取用户命令行字符串char usercommand[SIZE];int n = GetUserCommand(usercommand, sizeof(usercommand));if(n <= 0) return 1;//3.命令行字符串分割SplitCommand(usercommand, sizeof(usercommand));//4.检测命令是否是内键命令n = CheckBuildin();if(n) continue;//5,执行命令ExecuteCommand();}return 0;
}

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

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

相关文章

第5讲:建立自己的C函数库,js调用自己写的C/C++函数,并包含依赖C/C++第三方静态库。

在javascript中&#xff0c;Array有很多内置的功能&#xff0c;比如Array.map&#xff0c;Array.filter&#xff0c;Array.find等等&#xff0c;能用内置的功能就用内置的功能&#xff0c;最好不要自己实现一套&#xff0c;因为底层调用的可能压根就不是js语言本身&#xff0c;…

Wails 安装初体验

文章目录 Wails 安装说明1. 系统要求2. 安装步骤3. 构建应用 结论 Wails 安装说明 Wails 是一个用于构建桌面应用的 Go 框架&#xff0c;结合了现代前端技术。以下是安装步骤&#xff1a; 1. 系统要求 Go 1.16 或更高版本Node.js 和 npm可选&#xff1a;适用于 Windows、mac…

【机器学习】机器学习的重要方法——强化学习:理论,方法与实践

目录 一、强化学习的核心概念 二、强化学习算法的分类与示例代码 三.强化学习的优势 四.强化学习的应用与挑战 五、总结与展望 强化学习&#xff1a;理论&#xff0c;方法和实践 在人工智能的广阔领域中&#xff0c;强化学习&#xff08;Reinforcement Learning, RL&…

基于源码详解ThreadPoolExecutor实现原理

个人博客地址 基于源码详解ThreadPoolExecutor实现原理 | iwts’s blog 内容拆分 这里算是一个总集&#xff0c;内容太多&#xff0c;拆分成几个比较重要的小的模块&#xff1a; ThreadPoolExecutor基于ctl变量的声明周期管理 | iwts’s blog ThreadPoolExecutor 工作线程…

模板方法模式在金融业务中的应用及其框架实现

引言 模板方法模式&#xff08;Template Method Pattern&#xff09;是一种行为设计模式&#xff0c;它在一个方法中定义一个算法的框架&#xff0c;而将一些步骤的实现延迟到子类中。模板方法允许子类在不改变算法结构的情况下重新定义算法的某些步骤。在金融业务中&#xff…

可信和可解释的大语言模型推理-RoG

大型语言模型&#xff08;LLM&#xff09;在复杂任务中表现出令人印象深刻的推理能力。然而&#xff0c;LLM在推理过程中缺乏最新的知识和经验&#xff0c;这可能导致不正确的推理过程&#xff0c;降低他们的表现和可信度。知识图谱(Knowledge graphs, KGs)以结构化的形式存储了…

Python变量的命名规则与赋值方式

第二章&#xff1a;Python 基础语法 第一节&#xff1a;变量的命名规则与赋值方式 2.1.1 引言 在编程中&#xff0c;变量是存储数据的基本单元。变量的命名和赋值是编程语言中表达和操作数据的基础。了解和遵循变量命名规则对于编写清晰、可维护的代码至关重要。 2.1.2 变量…

【linux】网络基础(1)

文章目录 网络基本概念网络的定义网络的类型局域网&#xff08;LAN&#xff09;广域网&#xff08;WAN&#xff09; 网络协议OSI七层模型TCP/IP模型TCP/IP模型的结构 网络传输的基本流程计算机与计算机之间的通信计算机的信息处理封装报头 网络基本概念 网络的定义 1.网络是指…

专题一: Spring生态初探

咱们先从整体脉络上看下Spring有哪些模块&#xff0c;重要的概念有个直观印象。 从Spring框架的整体架构和组成对整体框架有个认知。 Spring框架基础概念 Spring基础 - Spring和Spring框架组成 上图是从官网4.2.x获取的原图&#xff0c;目前我们使用最广法的版本应该都是5.x&am…

一区算法MPA|海洋捕食者算法原理及其代码实现(Matlab/Python))

Matlab/Python&#xff1a; 本文KAU将介绍一个2020年发表在1区期刊ESWA上的优化算法——海洋捕食者算法 (Marine Predators Algorithm&#xff0c;MPA)[1] 该算法由Faramarzi等于2020年提出&#xff0c;其灵感来源于海洋捕食者之间不同的觅食策略、最佳相遇概率策略、海洋记…

【Linux】IO多路复用——select,poll,epoll的概念和使用,三种模型的特点和优缺点,epoll的工作模式

文章目录 Linux多路复用1. select1.1 select的概念1.2 select的函数使用1.3 select的优缺点 2. poll2.1 poll的概念2.2 poll的函数使用2.3 poll的优缺点 3. epoll3.1 epoll的概念3.2 epoll的函数使用3.3 epoll的优点3.4 epoll工作模式 Linux多路复用 IO多路复用是一种操作系统的…

MCU复位时GPIO是什么状态?

大家一定遇到过上电或者复位时外部的MOS电路或者芯片使能信号意外开启&#xff0c;至此有经验的工程师就会经常关心一个问题&#xff0c;MCU复位时GPIO是什么状态&#xff1f;什么电路需要外部加上下拉&#xff1f; MCU从上电到启动&#xff0c;实际可分为复位前和复位后、初始…

【WPF】Windows系统桌面应用程序编程开发新手入门-打造自己的小工具

电脑Windows系统上的桌面程序通常是用Visual Studio 开发工具编写出来的&#xff0c;有两种开发方式供选择&#xff0c;一种是WindowForm&#xff0c;简称WinForm&#xff0c;另一种是Windows Presentation Foundation&#xff0c;简称WPF&#xff0c;这里将学习WPF项目。 文章…

大物3错题整理

平衡位置&#xff1a;在O点上的位置 相位&#xff1a; 当N很大的时候&#xff0c;wxwywz。因此&#xff0c;平均平动动能除以3&#xff0c;就是能量均分定理。 W F在x上的积分 Π时无单位 180&#xff0c;就是单位 1rad&#xff0c;rad就是单位 左手定则、右手定则、安培定…

如何解决三菱软件提示 起动MELSOFT Mediative Server失败

前言&#xff1a; 注意&#xff0c;这篇文章仅针对如何解决 起动MELSOFT Mediative Server失败 的问题。对于其他相关的问题&#xff0c;请搜索其他相应的解决办法。 本人是在重装三菱GX Works软件时遇到此问题的。后来搜索发现无人能妥善的关闭这个提示。因此本文介绍如何关…

【Web3项目案例】Ethers.js极简入门+实战案例:实现ERC20协议代币查询、交易

苏泽 大家好 这里是苏泽 一个钟爱区块链技术的后端开发者 本篇专栏 ←持续记录本人自学智能合约学习笔记和经验总结 如果喜欢拜托三连支持~ 目录 简介 前景科普-ERC20 Ethers极简入门教程&#xff1a;HelloVitalik&#xff08;非小白可跳&#xff09; 教程概览 开发工具 V…

魔行观察-烤匠麻辣烤鱼-开关店监测-时间段:2011年1月 至 2024年6月

今日监测对象&#xff1a;烤匠麻辣烤鱼&#xff0c;监测时间段&#xff1a;2011年1月 至 2024年6月 本文用到数据源获取地址 魔行观察http://www.wmomo.com/ 品牌介绍&#xff1a; 2013年&#xff0c;第一家烤匠在成都蓝色加勒比广场开业&#xff0c;随后几年成都国金中心店…

超详细的tomcat安装以及简略项目的部署

一、安装包 安装路径&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1JzPQQ2zUdnXi_FaTTG0pvg?pwdriht 提取码&#xff1a;riht 安装完之后我们打开&#xff0c;可看见以下目录结构 二、环境变量配置 首先打开我们电脑的高级环境变量配置 我们先配置一个系统变量…

Variables Reference for vscode

Predefined variables Visual Studio Code 支持在调试、任务配置文件以及一些特定的设置中使用变量替换。这些变量可以使用 ${variableName} 语法在 launch.json 和 tasks.json 文件的某些键和值字符串中使用。 Predefined variables Visual Studio Code 支持以下预定义变量…

Zookeeper:Zookeeper JavaAPI操作与分布式锁

文章目录 一、Zookeeper JavaAPI操作1、Curator介绍2、创建、查询、修改、删除节点3、Watch事件监听 二、Zookeeper分布式锁原理 一、Zookeeper JavaAPI操作 1、Curator介绍 Curator是Apache Zookeeper的Java客户端。常见的Zookeeper Java API&#xff1a; 原生Java API。ZkC…