Linux进程控制——进程程序替换、bash的模拟实现

news2024/11/25 0:31:27

文章目录

    • exec系列函数
      • execl
      • execlp和execle
    • execv系列函数
    • bash的模拟实现
      • 实现思路
      • 完整代码
      • 其他问题

在学习进程的时候,我们想fork一个子进程,然后就可以给他布置任务了

但是如果我们分成两个人开发,父子进程分别负责不同的任务,等待开发完成之后除了合并项目或者复制粘贴还有更好的办法吗

其实是有的,当子进程被创建后不想执行父进程代码时,就需要用到程序替换

主要是exec系列函数的用法

exec系列函数

在这里插入图片描述

这里一共有六个函数,但是是同一个系列的,也有一定的规律,如果他们替换失败了,返回值都是-1

execl

这是里面最简单的函数,他的函数有两个,第一个是执行的程序路径,之后的是参数包,表示如何执行该程序

可以理解为前一个是环境变量,后一个是程序指令,只不过按单词分开,具体使用是这样的

例如

#include<stdio.h>
#include<unistd.h>
int main()    
{    
    printf("程序替换\n");    
    int n = execl("/usr/bin/ls","ls","-a","-l",NULL);
    if(n==-1)    
    {    
        perror("execl");    
    }    
    printf("程序替换\n");    
    return 0;    
}    

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结果是这样的,我们发现执行完execl之后执行了ls命令,而最后的输出命令却没有执行

说明execl之后,当前进程的代码和数据就和之前完全完全替换了,未执行的代码也会直接替换

execl的l是list的意思,其实就是要把执行程序的路径列举出来

execlp和execle

execlp的调用如下

#include<stdio.h>
#include<unistd.h>
int main()    
{    
    printf("程序替换\n");    
    int n = execlp("ls","-l",NULL);  
    if(n==-1)    
    {    
        perror("execlp");    
    }    
    printf("程序替换\n");    
    return 0;    
} 

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里我们可以发现execlp函数可以不用加路径,这其实是因为他可以自动检索环境变量,p的含义就是PATH

execle的调用如下

#include<stdio.h>
#include<unistd.h>
int main()    
{    
    const char* _env[]={"MY_ENV=114",NULL};    
    printf("进行程序\n");    
    int n = execle("/usr/bin/ls","ls","-l",NULL,_env); // 定义一个环境变量MY_ENV=114传递给要去执行的程序
    if(n==-1)    
    {    
        perror("execle");    
    }    
    printf("程序替换\n");    
    return 0;    
}  

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

execle可以在执行程序之前传入自己的环境变量,e是env的意思

execv系列函数

execv的v是vector的意思,也就是向量或者数组,可以理解为利用数组来传参

在这里插入图片描述

execv的使用如下

#include<stdio.h>
#include<unistd.h>
int main()    
  {    
	  char* const set[]={"ls","-a","-l",NULL};  
      printf("程序替换\n");    
      int n = execv("/usr/bin/ls",set); 
      if(n==-1)    
      {    
          perror("execv");    
      }    
      printf("程序替换\n");    
      return 0;    
  } 

这里的使用和上面其实差距不大,包括execvp和execvpe都是类似的,需要注意的是需要在最后加一个NULL表示数组结束

bash的模拟实现

一般情况下程序替换并非将自己进行替换,而是将fork出的子进程替换,自己来负责传达命令,回收子进程

实现思路

首先我们可以肯定的是bash是一共while死循环,因为他会不断的给我们打印提示信息

我们要模拟实现就可以自行定义其中的内容

例如

#include<stdio.h>
int main()
{
    while(true)
    {
        // 提示信息
        printf("[leaf @ MyBash]$ ");
        fflush(stdout);
        // ...
    }
    return 0;
}

在模拟实现之前我们需要梳理一下思路

bash的功能是将用户输入的字符串打散之后变成一共字符串数组,将这个字符串数组分配给子进程让他去进行程序替换,最后等待回收资源即可

这里我们可以确定的是需要保存完整的用户输入的命令行字符串,大三之后的字符串数组,之后还有一些细节进行处理

#define NUM 1000 // 一行命令最长字符数
#define SIZE 16 // 一行命令最多单词数
char input_line[NUM]; // 完整输入命令
char* line_argv[SIZE]; // 打散后的字符串数组
if(fgets(input_line, sizeof(input_line), stdin) == NULL) // fget保存到数组
    continue;
input_line[strlen(input_line)-1] = '\0'; // 覆盖换行

将整个字符串打散我们可以使用strtok函数

在这里插入图片描述

line_argv[0] = strtoc(input_line, " "); // 第一个单词
int index = 1;
while(line_argv[index++] = strtok(NULL, " ")); // 之后的每一个单词

这样最麻烦的处理用户输入的部分就解决了,完整代码如下

完整代码

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#define NUM 1000 // 一行命令最长字符数
#define SIZE 16 // 一行命令最多单词数
char input_line[NUM]; // 完整输入命令
char* line_argv[SIZE]; // 打散后的字符串数组

int main()
{
    while(1)
    {
        // 提示信息
        printf("[leaf@MyBash]$ ");
        fflush(stdout);
        
        // 获取输入
        memset(input_line, '\0', sizeof(input_line));
        if(fgets(input_line, sizeof(input_line), stdin) == NULL) // fget保存到数组
    		continue;
		input_line[strlen(input_line)-1] = '\0'; // 覆盖换行
        
        // 处理输入
        line_argv[0] = strtok(input_line, " "); // 第一个单词
		int index = 1;
		while(line_argv[index++] = strtok(NULL, " ")); // 之后的每一个单词
        
        // 子进程
        pid_t id = fork();
        if(id == 0)
        {
            printf("子进程\n");
            execvp(line_argv[0], line_argv);
            exit(1);
        }
        int status = 0;
        pid_t ret = waitpid(-1, &status, 0);
        if(ret > 0)
            printf("exit code: %d\n", WEXITSTATUS(status));
    }
    return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当然如果你愿意的话也可以获取当前的目录也打印在提示信息中

其他问题

我们之前介绍过内建命令,说这种命令只能让父进程调用,例如cd命令,因为写时拷贝,子进程进了某个文件夹,对父进程是没有影响的,也只有在父进程执行才有意义

if(strcmp(line_argv[0], "cd")==0)
{
    if(my_argv[1]!=NULL)
        chdir(my_argv[1]); // 切换当前工作目录
    continue;
}

还有例如export,kill,history都是内建命令

其实在Linux环境下,程序替换不仅可以替换C语言程序,甚至可以替换成Python程序、Java程序去执行他们的内部代码,这就变相实现了不同语言之间的联动

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

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

相关文章

揭秘智能工牌:如何成为房企销售团队的数字化转型加速器

在这个竞争激烈的市场环境中&#xff0c;房企想要脱颖而出&#xff0c;不仅需要优质的产品和服务&#xff0c;更需要高效的销售团队。而销售团队的能力提升&#xff0c;离不开精细化管理和科技的赋能。DuDuTalk智能语音工牌&#xff0c;正是这样一款融合了AI技术与销售实战智慧…

无人机之森林防火篇

无人机在森林火灾中的应用是一个快速发展的领域&#xff0c;它们在火灾预防、监测、救援和灾后评估等方面发挥着重要作用。 一、无人机在森林火灾监测中的应用 在森林火灾的监测方面&#xff0c;无人机凭借其高空、高速、长时间巡查的优势&#xff0c;能够全面覆盖监测区域&am…

体育器材管理系统(完整开发文档)

1.1研究背景及意义 研究背景&#xff1a; 体育器材是高校体育教学和课外体育活动的重要物质基础&#xff0c;其使用和管理对于保障教学质量、提高学生体育素质具有重要意义。随着高校体育教学和课外活动的不断发展&#xff0c;体育器材的种类和数量不断增加&#xff0c;传统的…

Linux进程(一)

目录 一.进程的介绍1.引出进程2.进程的介绍 二.创建进程1.创建进程的原理2.什么是fork函数(1).通过手册查看fork 3.例子 一.进程的介绍 1.引出进程 Google Chrome 是一个进程 Google Chrome 底下的选项是多个线程 通过top命令可以查看正在运行的进程 2.进程的介绍 课本概念 …

F5云安全防护能力如何?一文为你解惑

伴随云计算的快速发展&#xff0c;云安全已成为实施云战略的重要保障。来自F5 SOAS报告的调查显示&#xff0c;近三分之二的企业将使用AI和机器学习划入优先事项&#xff0c;并把云安全列为最关键的应用场景。作为一家提供多云应用安全和应用交付的公司&#xff0c;F5的云安全防…

python实现微信聊天图片DAT文件还原

完整代码如下&#xff1a; from glob import glob import os from tqdm import tqdmdef get_sign(dat_r):signatures [(0x89, 0x50, 0x4e), (0x47, 0x49, 0x46), (0xff, 0xd8, 0xff)]mats [".png", ".gif", ".jpg"]for now in dat_r:for j, x…

嵌入式行业,中年危机是否存在?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到高级教程」&#xff0c;点个关注在评论区回复“666”之后私信回复“666”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 肯定有&#xff0c;你看到的…

嵌入式人工智能(40-基于树莓派4B的水滴传感器和火焰传感器)

虽然这两个传感器水火不容&#xff0c;我还是把他们放到一起了。本文是有线传感器的最后一个部分了。后面如果还有文章介绍有线传感器&#xff0c;也是补充学习其他内容不得已而为之。如果不是&#xff0c;就当我没说&#xff0c;哈哈。 1、水滴传感器 水滴传感器又称雨滴传感…

实现字母的大小写转换。多组输入输出(c语言)

1.我们先输入字母&#xff08;用getchar的函数&#xff09;&#xff0c;判断是不是字母&#xff0c;我们可以用a<tmp<z或者A<tmp<Z,注意&#xff1a;小写转换大写用tmp-32&#xff0c;大写转换小写用tmp32.. #include<stdio.h> int main() {int a 0;while …

以太坊交易手续费计算

Gas 中译是&#xff1a;瓦斯、汽油&#xff0c;代表一种可燃气体。 这形象地比喻以太坊的交易手续费计算模式&#xff0c;不同于比特币中直接支付比特币作为转账手续费&#xff0c; 以太坊视为一个去中心化的计算网络&#xff0c;当你发送Token、执行合约、转移以太币或者在此区…

东巴古籍——纳西族古老文字的见证

关注我们 - 数字罗塞塔计划 - 华夏大地上的每个民族都有各自独特的文化传承&#xff0c;在前面的文章中&#xff0c;我们已经介绍过中国档案文献遗产名录中收录的永州女书和水族水书&#xff08;详细参见《永州女书——世上唯一专属于女性的文字》、《水书——破解象形文字含义…

二叉树LeetCode热题

94.二叉树的中序遍历 题目 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 输入&#xff1a;root [1,null,2,3]输出&#xff1a;[1,3,2] 代码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* …

一文搞懂大模型在多GPU环境的分布式训练!

随着大模型时代的到来&#xff0c;模型参数量、训练数据量、计算量等各方面急剧增长。大模型训练面临新的挑战&#xff1a; 显存挑战&#xff1a;例如&#xff0c;175B的GPT-3模型需要175B*4bytes即700GB模型参数空间&#xff0c;而常见的GPU显存如A100是80G显存&#xff0c;这…

zabbix使用脚本自定义监控项

1. 在zabbix_agent的配置文件中配置自定义key和脚本位置 vim /etc/zabbix/zabbix_agentd.confUserParametermq_check_log,/etc/zabbix/zabbix_agentd.d/mqlog.shmq_check_log&#xff1a;是这个自定义参数的名称。在Zabbix的监控项&#xff08;item&#xff09;配置中&#xf…

WinForm中使用Graphics画元素

前言 有时候我们需要在一个图像上显示一些文字&#xff0c;或者画一些标志&#xff0c;这就想我们平时截图也需要做一些描述信息。在C#中我们可以Graphics这个对象来绘制自己所需要描述的信息&#xff0c;当然在WPF中的它的设计思路又不一样了&#xff0c;在WPf中考虑使用的矩…

upload-labs靶场:1—10通关教程

目录 Pass-01&#xff08;JS 验证&#xff09; Pass-02&#xff08;MIME&#xff09; Pass-03&#xff08;黑名单绕过&#xff09; Pass-04&#xff08;.htaccess 绕过&#xff09; Pass-05&#xff08;大小写绕过&#xff09; Pass-06&#xff08;空格绕过&#xff09; …

经典神经网络(15)GLM模型原理详解及其微调(文本摘要)

经典神经网络(15)GLM模型原理详解及其微调(文本摘要) 2024年01月16日&#xff0c;智谱推出新一代基座大模型 GLM-4。新一代基座大模型 GLM-4 的整体性能相比上一代大幅提升&#xff0c;十余项指标逼近或达到 GPT-4&#xff1b;支持更长上下文&#xff1b;更强的多模态&#xf…

马丁短链02异常码 异常拦截器

全局统一返回实体&#xff1a; 目的是除了数据信息&#xff0c;还要带上一些错误状态码&#xff0c;成功与否&#xff0c;错误信息等等以帮助更好理解可能的错误。 规约&#xff1a;默认的约定 异常码设计原则&#xff1a; A客户端异常 B服务端异常 C远程调用异常 具体异常码…

CentOS7.9 利用 KubeKey 扩容 Kubernetes v1.26 Worker 节点实战

转载&#xff1a;CentOS7.9 利用 KubeKey 扩容 Kubernetes v1.26 Worker 节点实战 知识点 定级&#xff1a;入门级 KubeKey 安装部署 KubeSphere 和 Kubernetes KubeKey 定制化部署集群 KubeSphere v3.4.0 功能概览 Kubernetes 基本操作 CentOS 系统内核升级 演示服务器配…

Spring源码- context:component-scan base-package标签的作用源码解析

1.扫描包路径下所有的类加载解析成bean定义信息 ClassPathBeanDefinitionScanner .doScan方法调用路径 doScan:276, ClassPathBeanDefinitionScanner (org.springframework.context.annotation) parse:95, ComponentScanBeanDefinitionParser (org.springframework.context.a…