【Linux】12. 模拟实现shell

news2025/1/18 8:50:41

回顾

在之前的学习过程中,我们掌握了进程的相关概念,冯诺依曼体系结构,进程地址空间概念,进程状态,进程控制,进程退出,进程替换…等等一系列的基础知识,这些基础知识让我们清楚的知道进程从加载到运行到接收退出信息,操作系统是如何一步步进行控制的,也了解到相关操作系统的相关概念。
我们还学习到通过进程替换的方式,让操作系统使子进程执行另一个全新的进程却并未创建子进程的操作
在这里插入图片描述
废话不多说,直接开整!

1. 输出提示符

[hx@VM-12-2-centos myshell]$ cat myshell.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>

int main()
{
  printf("用户名@主机名 当前路径# ");
  fflush(stdout);
  sleep(10);
  return 0;
}

因为printf当中未带\n,所以要fflush(强制刷新缓冲区,将缓冲区的数据读取到显示器上)
在这里插入图片描述

2. 获取用户输入

在这里插入图片描述

3. 解决输入结尾带\n的问题

[hx@VM-12-2-centos myshell]$ cat myshell.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>

#define NUM 1024
char lineCommand[NUM];

int main()
{
  // 输出提示符
  printf("用户名@主机名 当前路径# ");
  fflush(stdout);
  
  // 获取用户输入
  char* s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);
  assert(s != NULL);
  // 清除最后一个\n
  lineCommand[strlen(lineCommand)-1] = 0;
  printf("test:%s\n",lineCommand);
  return 0;
}

在这里插入图片描述

4. 字符串切割

在这里插入图片描述

5. 测试切割是否成功

采用条件编译的方式进行测试,后续不想要测试随时取消#define定义值即可

[hx@VM-12-2-centos myshell]$ cat myshell.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>

#define NUM 1024
#define OPT_NUM 64

char lineCommand[NUM];
char *myargv[OPT_NUM];

int main()
{
  // 输出提示符
  printf("用户名@主机名 当前路径# ");
  fflush(stdout);
  
  // 获取用户输入
  char* s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);
  assert(s != NULL);
  // 清除最后一个\n
  lineCommand[strlen(lineCommand)-1] = 0;
  // printf("test:%s\n",lineCommand);
  
  // 字符串切割
  myargv[0] = strtok(lineCommand," ");
  int i = 1;
  while(myargv[i++] = strtok(NULL," "));

  //测试切割是否成功
#ifdef DEBUG 
  // myargv数组中最后1个是NULL 正好拿来判断循环结束
  for(int i = 0; myargv[i];i++)
  {
    printf("myargv[%d]:%s\n",i,myargv[i]);
  }
#endif
  return 0;
}

在这里插入图片描述

6. 嵌套循环

在这里插入图片描述

7. 执行命令

在这里插入图片描述
所以,到这里我们也就知道了shell底层执行命令行的原理:通过提取命令行上的指令对其分析(切割子串),再通过exec*系列接口调用所对应的命令来显示到显示器上。
乍一看好像已经实现完成了,还存在什么缺陷嘛?
在这里插入图片描述
ls在执行时并没有颜色上的区分

8. ls – 添加颜色

在这里插入图片描述

9. 内建命令cd

9.1 当前路径的认识

在这里插入图片描述
在这里插入图片描述
但这同样没有解决myshell当中cd切换不了路径的问题鸭,那么该如何理解呢?
shell在进行执行时,都是先通过fork创建子进程来执行对应的命令,那么也就是子进程执行的cd命令,子进程也存在自己的工作目录,当我们进行cd命令时更改的是子进程我的工作目录,当子进程执行完毕时,由父进程接收其返回值,之后使用的还是父进程shell,所以我们在父进程shell中观察不到子进程切换路径的现象

说了这么多,该如何操作实现呢?

9.2 增加内建命令cd的判断

在这里插入图片描述
对于这种不需要子进程执行,而是让shell执行的命令,我们称之为内建/内置命令

10. 内建命令echo $?

在这里插入图片描述

11. 最终代码

如下所示:

[hx@VM-12-2-centos myshell]$ cat myshell.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>

#define NUM 1024
#define OPT_NUM 64

char lineCommand[NUM];
char *myargv[OPT_NUM];
int lastCode = 0;
int lastSig = 0;

int main()
{
  while(1){
    // 输出提示符
    printf("用户名@主机名 当前路径# ");
    fflush(stdout);
  
    // 获取用户输入
    char* s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);
    assert(s != NULL);
    // 清除最后一个\n
    lineCommand[strlen(lineCommand)-1] = 0;
    // printf("test:%s\n",lineCommand);
  
    // 字符串切割
    myargv[0] = strtok(lineCommand," ");
    int i = 1;
    if(myargv[0] != NULL && strcmp(myargv[0],"ls") == 0)
    {
      myargv[i++] = (char*)"--color=auto";
    }

    while(myargv[i++] = strtok(NULL," "));

    if(myargv[0] != NULL && strcmp(myargv[0],"cd")==0)
    {
      if(myargv[1] != NULL)
      {
        chdir(myargv[1]);
      }
      continue;
    }
    if(myargv[0] != NULL && myargv[1] != NULL && strcmp(myargv[0],"echo")==0)
    {
      if(strcmp(myargv[1],"$?")==0)
      {
        printf("%d,%d\n",lastCode,lastSig);
      }
      else 
      {
        printf("%s\n",myargv[1]);
      }
      continue;
    }


    //测试切割是否成功
#ifdef DEBUG 
    for(int i = 0; myargv[i];i++)
    {
      printf("myargv[%d]:%s\n",i,myargv[i]);
    }
#endif 

    // 执行命令
    pid_t id = fork();
    assert(id != -1);
  
    // 子进程
    if(id == 0)
    {
      execvp(myargv[0],myargv);
      exit(100);
    }
    // 父进程
    int status = 0;
    pid_t ret = waitpid(id,&status,0);
    assert(ret>0);
    lastCode = ((status>>8) & 0xFF);
    lastSig = (status & 0x7F);
  }
  return 0;
}
[hx@VM-12-2-centos myshell]$ cat Makefile 
myshell:myshell.c
	gcc -o myshell myshell.c -std=c99 # -DDEBUG

.PHONY:clean
clean:
	rm -f myshell

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

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

相关文章

Qt6之字符串类内存分配新变化——16的次方增加

qt提供了比标准c string更强大&#xff0c;更丰富&#xff0c;更实用的字符串类QString&#xff0c;它的主要功能22个已经在之前逐一分析过&#xff0c;感兴趣的可前往以下链接查看&#xff0c;本文主要重点分析下qt在字符串类上面做的优化&#xff0c;主要是两个方面&#xff…

当产品进化遇见亿元福利,华帝携手人民日报为消费复苏添了一把火

这个五一黄金周&#xff0c;消费复苏的热火彻底被点燃。统计数据显示&#xff0c;2023年“五一”假期累计超过2.74亿人次出游&#xff0c;消费市场恢复到2019年同期水平。久违的“人间烟火气”再度回归。 除了旅游市场的火爆&#xff0c;同样助燃消费市场的还有全民“厨房焕新…

使用Vue+Python基于卷积神经网络前后端分离实现蔬菜种类预测系统

使用VuePython基于卷积神经网络前后端分离实现蔬菜种类预测系统 一、实现效果 1、种类预测界面 2、数据处理分析界面 3、网络模型界面 4、结果分析界面 二、需求分析 用户通过上传待预测图片到系统&#xff0c;系统预测出该图片对应的蔬菜种类&#xff0c;并且提示用户预测信…

基于Web的智慧储能电站3D可视化管理平台

电能作为现代社会的运转和发展的基础&#xff0c;是民生最基本的保障&#xff0c;其稳定性对国家经济发展至关重要。 建设背景 电力系统是一个稳态平衡系统&#xff0c;发电站的总发电功率需要等于用户端的总发电功率。如果两者不一致&#xff0c;就会导致整个电力系统的不稳…

[PyTorch][chapter 34][池化层与采样]

前言&#xff1a; 这里主要讲解一下卷积神经网络中的池化层与采样 目录 DownSampleMax poolingavg poolingupsampleReLu 1&#xff1a; DownSample 下采样,间隔一定行或者列进行采样&#xff0c;达到降维效果 早期LeNet-5 就采样该采样方式。 LeNet-5 2 Max pooling 最大值采样…

【28岁了,没有职业规划,没有目标,朋友推荐学云计算技术,能成吗?】

一般来说&#xff0c;当然可以的。云计算是一个不断发展的行业&#xff0c;不考虑年龄的因素&#xff0c;任何人都可以学习和掌握云计算的技能。28岁的年龄入行云计算是可行的&#xff0c;年龄方面还是符合企业的要求&#xff0c;而且云计算领域的发展趋势也显示出越来越多的企…

RIDGID里奇金属管线检测仪故障定位仪维修SR-20KIT

里奇RIDGID管线定位仪/检测仪/探测仪维修SR-20 SR-24 SR-60 美国里奇SeekTech SR-20管线定位仪对于初次使用定位仪的用户或经验丰富的用户&#xff0c;都同样可以轻易上手使用SR-20。SR-20提供许多设置和参数&#xff0c;使得大多数复杂的定位工作变得很容易。此外&#xff0c…

国内ChatGPT使用教程

猿说AI助手系统基于中国开源项目进行开发&#xff0c;由神诺网络科技工作室提供技术支持&#xff0c;后面我们会跟随官方持续更新。对话默认运行的是3.5-turbo模型&#xff0c;绘画采用Midjourney接口&#xff0c;待更新百度文心、通义千问、微信WeLM等。本系统仅用于技术研究&…

【k8s】【ELK】基于节点DaemonSet运行日志Agent实践【待写】

1.日志收集场景分析与说明 部署架构说明 对于那些将日志输出到&#xff0c;stdout与stderr的Pod&#xff0c; 可以直接使用DaemonSet控制器在每个Node节点上运行一个 <font colorred>filebeat、logstash、fluentd </font>容器进行统一的收集&#xff0c;而后写入…

论文阅读-DGM4-Detecting and Grounding Multi-Modal Media Manipulation

一、论文信息 论文名称&#xff1a;Detecting and Grounding Multi-Modal Media Manipulation 作者团队&#xff1a;南洋理工哈工大 Github:https://github.com/rshaojimmy/MultiModal-DeepFake 项目主页&#xff1a;https://rshaojimmy.github.io/Projects/MultiModal-DeepF…

在EasyCVR平台中添加设备提示成功但不显示是什么原因?

EasyCVR视频融合平台基于云边端智能协同架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;平台支持海量视频汇聚管理&#xff0c;可支持多协议接入&#xff0c;包括市场主流标准协议与厂家私有协议及SDK&#xff0c;如&#xff1a;国标GB28181、RTMP、RTSP/Onvi…

JECloud 运行前端模块所遇到的问题 汇总

1.依赖安装问题 官网 JECLoud 前端打包部署 1.1 部署前 注意 可以先下载 jecloud-libs 项目 尝试 部署安装 node版本不能过高&#xff01;选择node v14.17.5 版本 在部署前 如果当前node版本过高可以使用 nvm工具 切换到低版本&#xff0c; 但是需要注意的是 切换版本时 …

内网渗透(七十五)之域权限维持之DCShadow

DCShadow 2018年1月24日,在BlueHat安全会议上,安全研究员Benjamin Delpy 和 Vincent Le Toux 公布了针对微软活动目录域的一种新型攻击技术------DCShaow。利用该攻击技术,具有域管理员权限或企业管理员权限的恶意攻击者可以创建恶意域控,然后利用域控间正常同步数据的功能…

接口自动化测试-Requests之Session鉴权关联接口实战

目录 前言&#xff1a; 一、 简介 二、 实战操作 1. 登录接口 2. 查询订单接口 3. 新增订单接口 4. 修改订单接口 5. 删除订单接口 三、 结束语 前言&#xff1a; 接口自动化测试是软件测试过程中的重要一环&#xff0c;现在越来越多的公司开始使用自动化测试来提高测…

某社交平台 x-s所有可用

本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。 本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。 最新版 x-s 没露任何版权请审核员认真对待谢谢。 【2023.05.16】 更新全站接口通用 …

webpack食用指北

目录 何为webpackwebpack前置知识webpack项目初始化webpack配置文件运行webpack loadercss引入对loader的配置的几种写法 图片引入url的options自动清除上次打包遗留的资源 资源模块类型图片的webpack5引入方式字体的webpack5引入方式 webpack插件html-webpack-plugincopy-webp…

CSS 常用属性

padding (内边距):钻戒到盒子内边框的距离 margin (外边距):钻戒盒子距离桌子边缘的距离 border:钻戒盒子边框宽度 1) 内边距和外边距 内边距 外边距 使用方式: .a {padding: 10px 5px 15px 20px; /*上右下左*/padding: 10px 5px 15px; /*上右下*/padding: 10px 5px; /*上右…

EMC常见术语-dB、dBm、dBw以及如何计算

1. 手把手教&#xff1a;如何计算dB、dBm、dBw…… dB应该是无线通信中最基本、最习以为常的一个概念了。我们常说“传播损耗是xx dB”、“发射功率是xx dBm”、“天线增益是xx dBi”…… 有时&#xff0c;这些长得很像的dBx们可能被弄混&#xff0c;甚至造成计算失误。它们究…

docker Connection refused

环境介绍、服务版本、测试服务是否正常&#xff0c;可参考&#xff1a; docker could not find driver_龙枫995的博客-CSDN博客docker容器中&#xff0c;php和mysql互动时&#xff0c;解决出现could not find driverhttps://blog.csdn.net/longfeng995/article/details/130704…

Ngrok免费实现内网穿透

Ngrok免费实现内网穿透 前言 平时我们做项目&#xff0c;有时候需要用到内网穿透&#xff0c;让外网可以正常访问我们的资源。网上虽然有内网穿透工具&#xff0c;但是很多都是收费的&#xff0c;比如像我曾经用过的花生壳&#xff0c;好用是好用&#xff0c;但是要收费。我的…