在shell的命令行中输入命令,会有两种执行命令的途径

  1.         shell自己执行
  2.         shell创建子进程(fork ,exit ,waitpid,exec) ,子进程去执行

shell自己执行的命令是自建命令(bulit command)

子进程执行的是非自建命令

第一版只能维护命令行参数表+创建子进程, 执行非内建命令

        我们先创建了命令行提示符 ,获取了命令行的内容,维护了命令行参数表,创建了子进程进行命令的执行

​1 #include<iostream>2 #include<cstdio>3 #include<stdlib.h>4 #include<cstring>5 #include<string>6 #include<unistd.h>7 #include<sys/types.h>8 #include<sys/wait.h>9 10 using namespace std;11 const int charsize =1024;12 const int gargvnum =64;13 14 //全局的15 char* gargv[gargvnum];16 int gargc;17 18 19 int lastcode = 0;20 21 string GetUsrName()22 {23     string name =getenv("USER");24     return name.empty()?  "None" : name;25 }26 string GetHostName()27 {28     string name =getenv("HOSTNAME");29     return name.empty()?  "None" : name;30 }31 string GetPwd()32 {33     string name =getenv("PWD");34     return name.empty()?  "None" : name;35 }36 string MakeCommandLine()37 {  //[root@hcss-ecs-1f3a lesson17]#  38     char CommandLine[charsize];39     snprintf(CommandLine ,charsize,"[%s@%s %s]# ",\40         GetUsrName().c_str(),GetHostName().c_str(),GetPwd().c_str());41     return CommandLine;42 }43 void PrintCommandLine()//1.打印命令行提示符44 {45     printf("%s",MakeCommandLine().c_str());46     fflush(stdout);47 }48 49 50 bool GetCommand(char Command_buff[] ,int size)//2.获取命令51 {52     //将命令输出到字符数组中53     //ls -a -l -n54     char*result =fgets(Command_buff,size,stdin);55     if(!result)56     {57         return false;58     }59     Command_buff[strlen(Command_buff)-1]= 0;//fgets会将回车(\n)也输入60     if(strlen(Command_buff) == 0) return false;//strlen遇0(\0)会停下来61     return true;62 }63 64  void ParseCommand(char Command_buff[] ,int size)//3.分析命令65 {66     memset(gargv ,0,sizeof(gargv));67     gargc=0;68     const char* SEP =" ";69     gargv[gargc++] = strtok(Command_buff ,SEP);//strtok 会在字符串中查找分隔符,并将分隔符替换为 \0,从而将字符串分割成多个70     while((bool)(gargv[gargc++] = strtok(nullptr,SEP)));//strtok后续使用要用nullptr代替元字符串71     gargc--;72 }73 74 void debug()75 {76     printf("argc: %d\n", gargc);77     for(int i = 0; gargv[i]; i++)78     {79         printf("argv[%d]: %s\n", i, gargv[i]);80     }81 }85 bool ExecuteCommand()//4.执行命令86 {87     pid_t id =fork();88     if(id ==0)89     {//子进程90         int ret =execvp(gargv[0],gargv);91         if(ret ==-1) cout<<"子进程出错\n"<<endl;92         exit(1);93     }94     int status =0;95     pid_t rid =waitpid(id,&status ,0);96     if(rid >0)97     {98         if(WIFEXITED(status))99         {
100            lastcode=WEXITSTATUS(status);
101         }
102         else lastcode =100;
103         return true;
104     }
105     return false;
106 
107 }
108 
109 int main()
110 {
111     char Command_buff[charsize];
112     while(true)
113     {
114         PrintCommandLine();//1.打印命令行提示符
115 
116         if(!GetCommand(Command_buff,charsize))//2.获取命令
117         {
118             continue;
119         }
120         ParseCommand(Command_buff ,charsize);//3.分析命令
121         //debug();
122         ExecuteCommand();//4.执行命令
123     }
124     return 0;
125 }​

第一版的执行结果:

  • 第一版在执行cd ..时,是改变了子进程的cwd,子进程执行完又退了,无法影响下面的进程,cd.. 不能让子进程执行.
  • 所以cd .. 或cd / 是自建命令 ,需要shell自己执行,以便可以影响到下面的进程(例如在/ 目录下创建文件)

 第二版能维护命令行参数表+执行cd命令 ,判断了是否是自建命令(mysell自己执行自建命令,可以对环境变量发生改变),子进程执行其他命令.

在执行创建子进程前判断,命令是否是内建命令(是否是cd 命令),是否要创建子进程.

getpwd不再是从环境变量中拿,从pcb中拿(因为pcb中是实时的),拿完更新环境变量(命令行提示符每次运行都会刷新,借此来维护cd 后的环境变量).

    #include<iostream>2 #include<cstdio>3 #include<stdlib.h>4 #include<cstring>5 #include<string>6 #include<unistd.h>7 #include<sys/types.h>8 #include<sys/wait.h>9 10 using namespace std;11 const int charsize =1024;12 const int gargvnum =64;14 //全局的15 char* gargv[gargvnum];16 int gargc;17 19 20 21 //全局的当前shell的工作路径(定义到全局不会被销毁)22 char pwd[charsize];23 char pwdenv[charsize];24 25 int lastcode = 0;26 27 string GetUsrName()28 {29     string name =getenv("USER");30     return name.empty()?  "None" : name;31 }32 string GetHostName()33 {34     string name =getenv("HOSTNAME");35     return name.empty()?  "None" : name;36 }string GetPwd()38 {39     //string name =getenv("PWD");40     //return name.empty()?  "None" : name;41 42 43     //从pcb中直接拿pwd44     if(nullptr ==  getcwd(pwd,sizeof(pwd))) return "None";45     //拿到后还需要更新环境变量中的pwd46     snprintf(pwdenv,sizeof(pwdenv),"PWD=%s",pwd);47     putenv(pwdenv);48     return pwd;49 50 51 }52 string MakeCommandLine()53 {  //[root@hcss-ecs-1f3a lesson17]#  54     char CommandLine[charsize];55     snprintf(CommandLine ,charsize,"[%s@%s %s]# ",\56         GetUsrName().c_str(),GetHostName().c_str(),GetPwd().c_str());57     return CommandLine;58 }59 void PrintCommandLine()//1.打印命令行提示符60 {61     printf("%s",MakeCommandLine().c_str());62     fflush(stdout);63 }64 65 66 bool GetCommand(char Command_buff[] ,int size)//2.获取命令67 {68     //将命令输出到字符数组中69     //ls -a -l -n70     char*result =fgets(Command_buff,size,stdin);71     if(!result)72     {73         return false;74     }75     Command_buff[strlen(Command_buff)-1]= 0;//fgets会将回车(\n)也输入76     if(strlen(Command_buff) == 0) return false;//strlen遇0(\0)会停下来77     return true;78 }80  void ParseCommand(char Command_buff[] ,int size)//3.分析命令81 {82     memset(gargv ,0,sizeof(gargv));83     gargc=0;84     const char* SEP =" ";85     gargv[gargc++] = strtok(Command_buff ,SEP);//strtok 会在字符串中查找分隔符,并将分隔符替换为 \0,从而将字符串分割成多个86     while((bool)(gargv[gargc++] = strtok(nullptr,SEP)));//strtok后续使用要用nullptr代替元字符串87     gargc--;88 }89 90 void debug()91 {92     printf("argc: %d\n", gargc);93     for(int i = 0; gargv[i]; i++)94     {95         printf("argv[%d]: %s\n", i, gargv[i]);96     }97 }98 99 
100 
101 bool ExecuteCommand()//4.执行命令
102 {
103     pid_t id =fork();
104     if(id ==0)
105     {//子进程
106         int ret =execvp(gargv[0],gargv);
107         if(ret ==-1) cout<<"子进程出错\n"<<endl;
108         exit(1);
109     }
110     int status =0;
111     pid_t rid =waitpid(id,&status ,0);
112     if(rid >0)
113     {
114         if(WIFEXITED(status))
115         {
116            lastcode=WEXITSTATUS(status);
117         }
118         else lastcode =100;
119         return true;
120     }return false;
122 
123 }
124 
125 //内建命令的执行(调用函数,改变状态)
126 bool CheckandExecBuiltCommand()
127 {   //使用穷举法找内建命令
128     if(0 == strcmp(gargv[0],"cd"))
129     {
130         if(gargc == 2)
131         {
132             chdir(gargv[1]);
133         }
134         return true;
135     }
136     return false;
137 
138 }
139 
140 int main()
141 {
142     char Command_buff[charsize];
143     while(true)
144     {
145         PrintCommandLine();//1.打印命令行提示符
146 
147         if(!GetCommand(Command_buff,charsize))//2.获取命令
148         {
149             continue;
150         }
151         ParseCommand(Command_buff ,charsize);//3.分析命令
152         //debug();
153         //判断是否是内建命令,shell自己执行
154         if(CheckandExecBuiltCommand())//是内建命令并执行
155         {
156             continue;
157         }
158         //不是内建命令,创建子进程执行
159         ExecuteCommand();//4.执行命令
160     }
161     return 0;
162 }

第二版执行结果:

第三版 模拟真实shell从系统文件中获取环境变量,维护命令行参数表+维护环境变量表(execvpe)

  • myshell前面的两版都是从系统shell中获取的环境变量表
  • 实际上,系统shell开启时,是从系统文件中获取环境变量表,但是这个过程涉及shell脚本(比较难搞,意义不大),
  • 所以我们用将系统shell的环境变量表手动拷贝到myshell中的过程来模拟系统shell开启时,是从系统文件中获取环境变量表

  • 要让myshell执行的子进程的环境变量与myshell一致(不与系统shell一致)使用execvpe
  • 系统的shell维护了两张表(命令行参数表+环境变量表)

第三版拷贝了环境变量表,维护了环境变量表(exxcvpe),增加了内置命令

第三版运行结果:

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

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

相关文章

MySQL创建数据库和表,插入四大名著中的人物

一、登录数据库并创建数据库db_ck 二、创建表t_hero 表属性包括&#xff08;id&#xff0c;name&#xff0c;nickname&#xff0c;age&#xff0c;gender&#xff0c;address&#xff0c;weapon&#xff0c;types&#xff09; mysql> create table t_hero(-> id int,-…

静态网页的爬虫(以电影天堂为例)

一、电影天堂的网址&#xff08;url&#xff09; 电影天堂_免费电影_迅雷电影下载_电影天堂网最好的迅雷电影下载网&#xff0c;分享最新电影&#xff0c;高清电影、综艺、动漫、电视剧等下载&#xff01;https://dydytt.net/index.htm 我们要爬取这个页面上的内容 二、代码…

【C++】:STL详解 —— 红黑树封装map和set

目录 红黑树的源代码 正向迭代器的代码 反向迭代器的代码 set的模拟实现 map的模拟实现 红黑树的源代码 #pragma once #include <iostream>using namespace std; // set ->key // map ->key/value// set ->key // map ->key/valueenum Colour {RED,BLAC…

MATLAB控制函数测试要点剖析

一、功能准确性检验 基础功能核验 针对常用控制函数&#xff0c;像用于传递函数建模的 tf 、构建状态空间模型的 ss &#xff0c;以及开展阶跃响应分析的 step 等&#xff0c;必须确认其能精准执行基础操作。以 tf 函数为例&#xff0c;在输入分子与分母系数后&#xff0c;理…

MoonSharp 文档一

目录 1.Getting Started 步骤1&#xff1a;在 IDE 中引入 MoonSharp 步骤2&#xff1a;引入命名空间 步骤3&#xff1a;调用脚本 步骤4&#xff1a;运行代码 2.Keeping a Script around 步骤1&#xff1a;复现前教程所有操作 步骤2&#xff1a;改为创建Script对象 步骤…

ROS云课三分钟-差动移动机器人导航报告如何撰写-及格边缘疯狂试探

提示词&#xff1a;基于如上所有案例并结合roslaunch teb_local_planner_tutorials robot_diff_drive_in_stage.launch和上面所有对话内容&#xff0c;设计一个差速移动机器人仿真实验&#xff0c;并完成报告的全文撰写。 差速移动机器人导航仿真实验报告 一、实验目的 验证 T…

ACE协议学习1

在多核系统或复杂SoC&#xff08;System on Chip&#xff09;中&#xff0c;不同处理器核心或IP&#xff08;Intellectual Property&#xff09;模块之间需要保持数据的一致性。常用的是ACE协议or CHI。 先对ACE协议进行学习 ACE协议&#xff08;Advanced Microcontroller Bu…

ajax之生成一个ajax的demo示例

目录 一. node.js和express ​二. 使用express创建后端服务 三. 创建前端 一. node.js和express ajax是前端在不刷新的情况下访问后端的技术&#xff0c;所以首先需要配置一个后端服务&#xff0c;可以使用node.js和express。 首先生成一个空项目&#xff0c;新建main目录…

Java 字节码操纵框架 -ASM

Java 字节码操纵框架 -ASM 1.ASM 概述: ASM 是用于 Java 字节码操纵的框架,可动态生成新类或增强现有类的功能。它既能直接产生二进制 class 文件,也能在类被加载到虚拟机之前动态改变类行为,通过读取类文件信息来分析、修改类行为,甚至生成新类。许多流行框架如 cglib、…

kafka + flink +mysql 案例

假设你有两个Kafka主题&#xff1a;user_activities_topic 和 product_views_topic&#xff0c;并且你希望将user_activities_topic中的数据写入到user_activities表&#xff0c;而将product_views_topic中的数据写入到product_views表。 maven <dependencies><!-- …

远程登录客户端软件 CTerm 发布了 v4.0.0

有时候我们需要远程登录到 Linux/Unix 服务器&#xff0c;这方面使用最广泛的客户端软件是 PuTTY&#xff0c;不过它是全英文的&#xff0c;而且是单窗口的&#xff0c;有时候显得不那么方便。 CTerm (Clever Terminal) 是一个 Windows 平台下支持 Telnet 和 SSH 协议进行远程…

从李佳琦团队看新型用工:灵活就业如何重构组织架构?

2022年“双11”期间&#xff0c;李佳琦直播间累计销售额突破115亿元&#xff08;来源&#xff1a;新腕数据《2022双11直播电商战报》&#xff09;&#xff0c;其背后团队规模约400人&#xff0c;但全职员工仅占35%&#xff0c;其余65%为外包选品团队、兼职客服、第三方MCN机构人…

微软程序的打包格式MSIX

MSIX 微软推出的MSIX格式是其为统一Windows应用程序打包和部署而设计的新一代安装包格式&#xff0c;具有以下核心特点和进展&#xff1a; 1. 推出背景与时间线 MSIX最初于2018年在微软Build大会上宣布&#xff0c;并在同年7月发布预览版打包工具&#xff0c;10月正式版上线…

AFL++安装

学习fuzzing也几天了&#xff0c;今天记录AFL的安装及使用 一、实验环境 虚拟机&#xff1a;ubuntu20.04 当然也可以uname -a去看自己的版本号 二、AFL安装 1.先更新一下工具 sudo apt update2.安装AFL必要的一些依赖&#xff0c;例如编译工具&#xff08;如 build-essen…

【STM32】ADC功能-单通道多通道(学习笔记)

本章结合上一节内容复习更好理解【江协科技STM32】ADC数模转换器-学习笔记-CSDN博客 一、ADC单通道 接线图 ADC初始化 ①RCC开启时钟&#xff0c;包括ADC和GPIO的时钟&#xff0c;另外ADCCLK的分频器也要配置 ②配置GPIO,&#xff0c;把需要用的GPIO配置成模拟输入模式&am…

基于YOLO11深度学习的运动品牌LOGO检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

当前主流的大模型训练与推理框架的全面汇总

以下是当前主流的大模型训练与推理框架的全面汇总 以下是更新后包含 SGLang 的大模型训练与推理框架列表&#xff0c;并对分类和示例进行了优化&#xff1a; 一、通用深度学习推理框架 TensorRT-LLM 特点&#xff1a;NVIDIA推出的针对Transformer类模型的优化框架&#xff0c;支…

Linux学习(八)(服务管理(检查服务状态,开始/停止服务,检查服务日志,创建新服务))

服务管理 Linux 中的服务管理是指控制 Linux 在启动和关闭计算机的过程中启动和停止的服务&#xff08;或“守护程序”&#xff09;的系统。这些服务执行各种功能&#xff0c;并提供未附加到用户界面的进程。 Linux 系统&#xff0c;尤其是系统管理员&#xff0c;通常需要管理…

ElasticSearch 分词器介绍及测试:Standard(标准分词器)、English(英文分词器)、Chinese(中文分词器)、IK(IK 分词器)

ElasticSearch 分词器介绍及测试&#xff1a;Standard&#xff08;标准分词器&#xff09;、English&#xff08;英文分词器&#xff09;、Chinese&#xff08;中文分词器&#xff09;、IK&#xff08;IK 分词器&#xff09; ElasticSearch 分词器介绍及测试1. Standard Analyz…

【计算机网络】确认家庭网络是千兆/百兆带宽并排查问题

要确认你的带宽是千兆&#xff08;1000Mbps&#xff09;还是百兆&#xff08;100Mbps&#xff09;&#xff0c;可以通过以下方法逐步排查&#xff1a; 一、检查物理设备 1. 查看路由器和光猫的网口 千兆网口&#xff1a;路由器或光猫的网口旁通常会标注 “10/100/1000M” 或 …