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

news2024/12/24 2:37:01

目录

前言

替换的原理

替换函数

记忆技巧

函数使用

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 16

int 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 16

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);
    //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.coloradmin.cn/o/1571270.html

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

相关文章

python标准数据类型--集合常用方法

在Python中&#xff0c;集合&#xff08;Set&#xff09;是一种无序且不重复的数据结构&#xff0c;它是由一个无序的、不重复的元素组成的。Python中的集合与数学中的集合概念相似&#xff0c;并且支持一系列常用的方法。本篇博客将深入介绍Python集合的常用方法&#xff0c;帮…

亚马逊跨境电商平台真人测评和自养号测评有什么区别?

下面来讲一下真人测评和自养号测评的优缺点有哪些 真人测评 优点&#xff1a;权重高&#xff0c;可以有效提升转化率 缺点&#xff1a;市面上的渠道良莠不齐&#xff0c;质量难以保证&#xff0c;且较难选择 真人测评是通过真人的买家在页面留下review的方式来提高权重&…

【51单片机入门记录】A/D、D/A转换器PCF859应用

目录 一、IIC初始化代码 二、开发板电路图 三、PCF8591读/写字节操作流程及相关函数 &#xff08;1&#xff09;PCF8591&#xff08;AD&#xff09;读操作流程及代码 &#xff08;2&#xff09;PCF8591&#xff08;AD&#xff09;写操作流程及代码 四、应用示例-显示电压…

c# wpf template itemtemplate+ListBox

1.概要 2.代码 <Window x:Class"WpfApp2.Window7"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend/…

Nuxt 项目的创建

中文文档&#xff1a;https://nuxt.com.cn/docs/getting-started/installation#%E6%96%B0%E9%A1%B9%E7%9B%AE Nuxt 项目创建的先决条件&#xff1a; Node.js 版本 18.0.0 及以上文本编辑器&#xff1a;VS Code Volar 插件 或 Webstorm 执行如下命令&#xff0c;创建 Nuxt 项目…

【MATLAB】GA_BP神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 GA_BP神经网络时序预测算法是一种结合了遗传算法(GA)和反向传播(BP)神经网络的时序预测方法。它利用了遗传算法的全局搜索和优化能力&#xff0c;以及BP神经网络的学习和逼近能力&#xff0c;可以更有效地预…

[java]网络编程

网络编程概述 计算机网络&#xff1a; 把分布在不同地理区域的具有独立功能的计算机,通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统。 Java是 Internet 上的语言&#xff0c;它从语言级上提供了对网络应用程序的支持&#xff0c;程序…

【MySQL】聚合函数和分组聚合

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习计网、mysql和算法 ✈️专栏&#xff1a;MySQL学习 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac…

渗透测试靶机----Raven-1

渗透测试靶机----Raven-1 开启靶机&#xff0c;登录窗&#xff0c;平平无奇 开扫&#xff1a; 先看看ip 这里发现192.168.217.166 发现相关服务端口&#xff0c;这里看到80&#xff0c;还是老样子&#xff0c;先80入手打开发现一个熟悉的站点&#xff1a; 这里可以使用漏扫工具…

解密项目管理工具数据安全:防火防盗,保密有招

相关数据显示&#xff0c;2021年中国数字经济规模总量达到45.5万亿元&#xff0c;占到国内GDP总量的39.8%。数字经济已经渗入我们工作生活的方方面面&#xff0c;项目管理工具就是其中之一&#xff0c;在数据安全备受重视的今天如何保证项目管理工具的数据安全性&#xff1f;Zo…

C-开发 visual Studio扩展插件介绍-格式化插件Xaml Styler、CSharpier介绍(扩展插件安装方法)

C#开发 visual Studio扩展插件介绍 扩展插件安装方法Xaml StylerCSharpier 提高C#开发效率常用的插件 扩展插件安装方法 菜单栏点击“扩展”→“管理扩展”。 打开扩展页面 右上角搜索需要安装的插件&#xff0c;然后点击下载 安装完成后&#xff0c;根据提示关闭VS进行安…

MPEG-1 详解

MPEG-1 详解 MPEG-1 详解特点MPEG-1 中的运动补偿与 B 帧的引入MPEG-1 vs H.261MPEG-1 视频数据流的结构MPEG-1 视频压缩模式MPEG-1 视频解码框图MPEG-1 音频编码模式MPEG-1 audio layer 1MPEG-1 audio layer 2MPEG-1 audio layer 3 MPEG-1 音频编码框图MPEG-1 音频解码框图参考…

大数据实验四-MapReduce编程实践

一&#xff0e;实验内容 MapReduce编程实践&#xff1a; 使用MapReduce实现多个文本文件中WordCount词频统计功能&#xff0c;实验编写Map处理逻辑、编写Reduce处理逻辑、编写main方法。 二&#xff0e;实验目的 1、通过实验掌握基本的MapReduce编程方法。 2、实现统计HDF…

使用阿里云试用Elasticsearch学习:1.2 基础入门——数据输入和输出

什么是文档? 在大多数应用中&#xff0c;多数实体或对象可以被序列化为包含键值对的 JSON 对象。 一个 键 可以是一个字段或字段的名称&#xff0c;一个 值 可以是一个字符串&#xff0c;一个数字&#xff0c;一个布尔值&#xff0c; 另一个对象&#xff0c;一些数组值&#…

Linux+HA高可用24X7的安全保证

一&#xff0e; 介绍作为服务器&#xff0c;需要提供一定的24X7的安全保证&#xff0c;这样可以防止关键节点的宕机引起系统的全面崩溃。利用OpenSource开源软件&#xff0c;完成系统的高可靠双机热备方案。基于linux的 HA软件可靠稳定&#xff0c;比使用商业版本的HA软件降低成…

中国智慧城管哪家做的好?

智慧城市管理综合执法系统建立全市统一的法律法规、裁量基准、执法事项、执法文书和基础信息库&#xff0c;实现从获取线索、立案、调查、处理到结案全过程的信息化和文书制作的智能化。全面支持移动执法办案&#xff0c;提高执法效率。 技术架构&#xff1a; 微服务javasprin…

arm开发板移植工具mkfs.ext4

文章目录 一、前言二、手动安装e2fsprogs1、下载源码包2、解压源码3、配置4、编译5、安装 三、移植四、验证五、总结 一、前言 在buildroot菜单中&#xff0c;可以通过勾选e2fsprogs工具来安装mkfs.ext4工具&#xff1a; Target packages -> Filesystem and flash utilit…

【Python】免费的图片/图标网站

专栏文章索引&#xff1a;Python 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 这里是我收集的几个免费的图片/图标网站&#xff1a; iconfont-阿里巴巴矢量图标库icon&#xff08;.ico&#xff09;INCONFINDER&#xff08;.ico&#xff09;

力扣刷题 二叉树的迭代遍历

题干 给你二叉树的根节点 root &#xff0c;返回它节点值的 前中后序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root […