【Linux】进程程序替换 &&简易mini_shell实现

2023-10-27

替换原理

目前,我们使用fork创建子进程,为了用if,else让子进程执行父进程代码的一部分。如果想让子进程执行一个全新的程序,进程不变,仅仅替换当前进程的代码和数据,就叫做 进程替换

在这里插入图片描述

子进程往往要调用一种exec函数,执行另一个程序,当进程调用一种exec函数时。进程的用户空间代码和数据被新程序完全替换。调用exec函数前后进程的id不变。

程序替换的本质:把指定的代码和数据,加载到特定进程的上下文中。
C/C++程序要运行,必须通过 加载器先加载到内存。
方式:exec*程序替换函数。

替换函数

在Linux下使用man 3 exec查看:
在这里插入图片描述

在这里插入图片描述

六种函数都是以exec开头的吗,称为exec函数。

exec函数的返回值:
成功时,函数不返回。失败时,函数返回-1。

-> 所以exec函数只有出错的返回值而没有成功的返回值。只要exec*返回了,就一定时因为调用失败了。

替换函数的使用

execl:
int execl(const char *path, const char *arg, ...);

path:要执行的目标程序的全路劲,所在路径/文件名形式,来表示你要执行谁
arg:表示你要执行的目标程序在命令行上怎么执行,这里的参数就怎么一个一个的传递进去,和命令行上的形式一样!
… :因为时可变参数列表,所以必须用NULL结尾!

接下来看7个函数原型:

#include <unistd.h>

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
int execve(const char* path, char* const argv[], char* const envp[]);

简单的理解方法:

l:表示arg参数用列表传,const char* arg, ...

在这里插入图片描述
v:arg参数用数组传,char* const argv[]

在这里插入图片描述

p:有p自动搜索环境变量 PATH,不需要自己写路径。

在这里插入图片描述

e:自己维护环境变量(自定义环境变量)

所有的接口,差别并不大,只是参数不同。设置这么多接口,是为了满足不同的应用场景。

在这里插入图片描述
在这里插入图片描述

只有execve时真正的系统调用,其他五个函数最终都调用execve,在man手册用 man 2 exec可以查看,其他函数在man 3 exec可以查看。

execve的demo:

char *env[] = {
    "MYENV1_xxxxxxxxxxxxxxxxxxxxxxxxxx",
    NULL
  };

execle("./myload", "myload", NULL, env);

简易shell实现程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>

#define NUM 128
#define CMD_NUM 64

int main()
{
  char command[NUM];
  for(; ;)
  {
    char *argv[CMD_NUM] = {NULL};
    // 1、打印提示符
    command[0] = 0; //用这种方式,可以做到O(1)时间复杂度,清空字符串
    printf("[zjy@myhostname mydir]# ");
    fflush(stdout);
    // 2、获取命令字符串
    fgets(command, NUM, stdin);
    command[strlen(command)-1] = '\0';
    printf("echo: %s\n", command);
   
    // ls -a -l -d\0
    // 3、解析命令字符串  strtok
    const char *sep = " ";
    argv[0] = strtok(command, sep);
    int i = 1;
    while(argv[i] = strtok(NULL, sep))
    {
      ++i;
    }

    // 4、检测命令是否是需要shell本身执行的,内建命令
    if(strcmp(argv[0], "cd") == 0)
    {
      if(argv[1] != NULL)
        chdir(argv[1]);
        continue;
    }

    // 5、执行第三方命令
    if(fork() == 0)
    {
      // child
      execvp(argv[0], argv);
      exit(1);
    }

    // father
    waitpid(-1, NULL, 0);
    
    
    // for(i=0; argv[i]; ++i)
    // {
    //   printf("%s\n", argv[i]);
    // }
    

  }
  return 0;
}

注意点:

fork()执行的命令是第三方命令(独立的),但是cd不是,cd回退只是子进程回退,但是当子进程结束后,父进程还在原来的路径下,所以这时,不能创建子进程,要让父进程自己执行,可以调用 chdir函数。不能用程序替换,如果使用,会导致整个代码发生改变,不能继续循环输入了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux】进程程序替换 &&简易mini_shell实现 的相关文章

随机推荐

  • android 异步加载图片缩略图

    建一个AsyncLoadedImage类继承AsyncTask异步加载类 调用publishProgress方法更新onProgressUpdate贮存缩略图信息到Adapter 监听Adapter Change实现异步加载缩略图 main
  • Go基础(复杂类型):函数的闭包

    函数的闭包 Go 函数可以是一个闭包 闭包是一个函数值 它引用了其函数体之外的变量 该函数可以访问并赋予其引用的变量的值 换句话说 该函数被 绑定 在了这些变量上 例如 函数 adder 返回一个闭包 每个闭包都被绑定在其各自的 sum 变
  • OpenCV快速傅里叶变换(FFT)用于图像和视讯流的模糊检测

    OpenCV快速傅里叶变换 FFT 用于图像和视频流的模糊检测 翻译自 OpenCV Fast Fourier Transform FFT for blur detection in images and video streams 原文链
  • PHP实现一个简单的登录和注册,以及实现方法和页面

    下面是一个简单的PHP代码示例 实现了登录和注册功能 首先 创建一个名为index php的文件 用于显示登录和注册表单 h2 登录 h2
  • Linux 安装JDK17

    1 官网下载JDK17 这里我们下载的是 x64 Compressed Archive版本 2 解压tar 文件 进入文件下载目录 自己定义 我这里都放在software cd usr local softwar 解压tar文件 tar v
  • 【毕业项目】自主设计HTTP

    博客介绍 运用之前学过的各种知识 自己独立做出一个HTTP服务器 自主设计WEB服务器 背景 目标 描述 技术特点 项目定位 开发环境 WWW介绍 网络协议栈介绍 网络协议栈整体 网络协议栈细节 与http相关的重要协议 HTTP背景知识补
  • 最强自动化测试框架Playwright(11)- 录制视频

    视频 使用playwright 您可以录制测试视频 录制视频 视频在测试结束时在浏览器上下文关闭时保存 如果手动创建浏览器上下文 请确保等待 browser context close context browser new context
  • 分布式任务调度可选方案

    1 除了基于jvm的java之处 新接触一个JVM语言 SCALA 一种同时面向脚本和面向函数的语言 spark大数据框架是基于scala语言 照着网络教程 简单的写了几个例子 感觉object class与java语境中还是有一定的差异
  • 2023美赛F题完整数据代码模型成品文章思路-- Green GDP

    论文摘要 模型和其他部分内容如下 摘要 现行的以GDP为核心的国民经济核算体系 由于忽略非市场产出 环境破坏 资源浪费方面的有关计算 这样的指标并不完整 由于经济活动中 对资源消耗和对环境的负面影响越来越大 而长期忽略这种负面影响的后果 高
  • Hexo在多台电脑上提交和更新

    文章目录 1 博客搭建 2 创建一个新文件夹new 用于上传hexo博客目录 3 github上创建hexo分支并设置为默认分支 创建hexo分支 将hexo分支设置为默认分支 4 进入新建的文件夹中git clone 再上传相关文件至he
  • navicat for mysql 连接 mysql 出现1251错误

    navicat for mysql下载地址 链接 https pan baidu com s 1Nh2ippFKHrWXnzPx hda8g 密码 fumf 客户端使用navicat for mysql 本地安装了mysql 8 0 但是在
  • CVE-2023-35843:NocoDB任意文件读取漏洞复现

    文章目录 NocoDB 存在任意文件读取漏洞CVE 2023 35843 0x01 前言 0x02 漏洞描述 0x03 影响范围 0x04 漏洞环境 0x05 漏洞复现 1 访问漏洞环境 2 构造POC 3 复现 0x06修复建议 Noco
  • zookeeper选举流程源码分析

    zookeeper选举流程源码分析 选举的代码主要是在QuorumPeer java这个类中 它有一个内部枚举类 用来表示当前节点的状态 public enum ServerState LOOKING FOLLOWING LEADING O
  • 关于vue项目的node、node-sass、sass-loader的版本问题

    后续博客全部搬迁至个人博客 欢迎访问 最近遇到一个问题 在下载vue项目的node modules的包时 node sass和sass loader版本总是不匹配 当两者匹配时 node和node sass版本又不匹配 导致我的服务一直起不
  • 简历中场景

    场景一 消息的发送 接收 利用rabbitmq的单通道模式 实现专家端发送消息 老师端监听消息 流程 subject accept server中producer消息 mq message中consumer监听消息 并保存在数据库中 调用m
  • 安装potobuf(make check通过)

    很多文章中给出的方法是在github上下载项目 然后创建build再安装googletest 但是在最后的make check时一直报错 如果是python中使用 直接sudo pip3 install i https pypi tuna
  • Spring 3整合Quartz 2实现定时任务一:常规整合

    最近工作中需要用到定时任务的功能 虽然Spring3也自带了一个轻量级的定时任务实现 但感觉不够灵活 功能也不够强大 在考虑之后 决定整合更为专业的Quartz来实现定时任务功能 首先 当然是添加依赖的jar文件 我的项目是maven管理的
  • Cannot run program “D:\Environment\jdk1.8\bin\java.exe”解决方法

    Cannot run program D Environment jdk1 8 bin java exe in directory D Project Java Idea project docker springboot CreatePr
  • Scratch的广播与消息

    在事件积木中 有一块触发积木叫当接收到 消息1 对应地 有两块积木 广播 消息1 广播 消息1 并等待 广播 消息机制就是编程中的全局事件 当一个消息被广播时 所有角色 包含广播者自身 都会接收到该消息 只要一个角色有该消息的接收脚本 即可
  • 【Linux】进程程序替换 &&简易mini_shell实现

    文章目录 替换原理 替换函数 替换函数的使用 简易shell实现程序 替换原理 目前 我们使用fork创建子进程 为了用if else让子进程执行父进程代码的一部分 如果想让子进程执行一个全新的程序 进程不变 仅仅替换当前进程的代码和数据