Linux 模拟实现shell【简单实现】

shell的模拟实现

我们知道shell是一个永不退出的程序,所以他应该是一个死循环,并且shell为了防止影响到自己,我们在命令行上输入的所有命令都是由shell的子进程来执行的,所以它应该要有创建子进程的相关函数,当然也会有进程替换的相关函数,因为我们直接创建子进程,父子进程是共享代码的,如果没有进程替换,shell根本无法让子进程执行特定的命令。

总的思路:
1.打印提示符 && 获取用户命令字符串
2.分割字符串
//“ls -a -l” —> “ls” “-a” “-l”
3.check buildin command 检查内键命令
4.执行命令

1.打印提示符 && 获取用户命令字符串

在这里插入图片描述

对于getUserCommand函数:

先介绍fgets函数:在这里插入图片描述

#define NUM 1024
#define SIZE 64int getUserCommand(char *command,int num)
{printf("[%s@%s %s]",getUsername(),getHostname(),getCwd());//不用scanf,遇到空格会停,不好用char *r = fgets(command,num,stdin);//最终还是会输入\nif(r == NULL) return -1;//abcd\ncommand[strlen(command) - 1] = '\0';//给最后加上\0return strlen(command);
}

getUsername(),getHostname(),getCwd() 是为了读取用户名@主机名 当前所在文件夹

在这里插入图片描述

2.分割字符串

比如我要执行ls命令,ls命令后还可以携带选项,ls -a -l,shell需要获取指令与选项,并将它们分割(shell接收到的是一串字符串"ls -a -l",shell需要将字符串分割为更小的字符串"ls" “-a” “-l”)。

定义char usercommand[NUM];接收一整行的指令,该数组中的元素保存的是字符,char *argv[SIZE];//存储命令拆分后结果,该数组中的元素要保存的是分割后的字符串。
在这里插入图片描述

介绍strtok:
在这里插入图片描述

void commandSplit(char *in,char *out[])
{int argc = 0;out[argc++] = strtok(in," ");//分隔并放入out指针数组while(out[argc++] = strtok(NULL," "));
}

3.check buildin command 检查内键命令

在这里插入图片描述

内建命令:

开头说到,shell的命令分为内部命令和其他命令,何为内建命令? 内建命令是一个需要shell自己执行的命令,即shell不创建子进程,自己亲自执行的命令。

shell对于一些命令是必须要亲自执行的:比如cd更改工作路径,将shell的工作路径修改后,由于子进程的工作路径与父进程相同,更改分进程的工作路径后,父进程创建出的子进程的工作路径也是被修改过的,体现给用户的感觉就是当前的工作路径改变了。

对于内建命令,shell是怎么实现的? shell中有许多内建命令,当shell接收到指令并解析后,需要判断用户输入的命令是否为内建命令,如果是就执行拦截操作,使子进程不再被创建,自己执行该指令。如果不是内建命令,则创建子进程执行该命令。

内建命令太多,代码里面只写了cd和export内建命令。

char cwd[1024];//全局变量
char enval[1024];//for test char *homepath()
{char *home = getenv("HOME");if(home) return home;else return (char*)".";
}void cd(const char *path)
{chdir(path);//chdir(),用户将当前的工作目录改变成以参数路径所指的目录char tmp[1024];getcwd(tmp,sizeof(tmp));//getcwd()会将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,参数size为buf的空间大小。sprintf(cwd,"PWD=%s",tmp); //打印到字符串中putenv(cwd);//putenv 函数会将cwd 直接填写到环境表中
}// 什么叫做内键命令: 内建命令就是bash自己执行的,类似于自己内部的一个函数!
// 1->yes, 0->no, -1->err
int doBuildin(char* argv[])
{if(strcmp(argv[0],"cd") == 0) //cd ...{char *path =  NULL;if(argv[1] == NULL) path = homepath();//纯cd,回到HOMEelse path = argv[1];cd(path);//进入要进入的路径return 1;}else if(strcmp(argv[0],"export") == 0){if(argv[1] == NULL) return 1;strcpy(enval,argv[1]);//拷贝putenv(enval);//直接填写到环境表中return 1;}return 0;
}

对于void cd(const char *path),用 chdir() 函数来将 用户当前的工作目录改变成以参数路径所指的目录,
用 getcwd() 函数将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,
用 sprintf() 函数将 “PWD=工作目录” 字符串打印给cwd,
用putenv 将cwd 直接填写到环境表中。

4.执行命令

在这里插入图片描述

int execute(char *argv[])
{pid_t id = fork();if(id < 0) return -1;else if(id == 0) //child{//exec commandexecvp(argv[0],argv);//execvp()会从环境变量所指的目录中查找符合参数 file 的文件名, 找到后执行该文件, 然后将第二个参数argv 传给该执行的文件。exit(1);}else //father{int status = 0;pid_t res = waitpid(-1, &status, 0);//阻塞式等待if(res > 0)//等待成功{printf("exit code: %d \n", WEXITSTATUS(status));}}return 0;
}

用子进程进行进程替换,执行命令:

在进行进程替换时,使用ececvp()函数:
在这里插入图片描述

效果动态图

在这里插入图片描述

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>#define NUM 1024
#define SIZE 64char cwd[1024];
char enval[1024];//for test char *homepath()
{char *home = getenv("HOME");if(home) return home;else return (char*)".";
}const char *getUsername()
{const char *name = getenv("USER");if(name) return name;else return "none";
}const char *getHostname()
{const char *hostname = getenv("HOSTNAME");if(hostname) return hostname;else return "none";
}const char *getCwd()
{const char *cwd = getenv("PWD");if(cwd) return cwd;else return "none";
}int getUserCommand(char *command,int num)
{printf("[%s@%s %s]",getUsername(),getHostname(),getCwd());//不用scanf,遇到空格会停,不好用char *r = fgets(command,num,stdin);//最终还是会输入\nif(r == NULL) return -1;//abcd\ncommand[strlen(command) - 1] = '\0';return strlen(command);
}void commandSplit(char *in,char *out[])
{int argc = 0;out[argc++] = strtok(in," ");//分隔并放入out指针数组while(out[argc++] = strtok(NULL," "));
}void cd(const char *path)
{chdir(path);//chdir(),用户将当前的工作目录改变成以参数路径所指的目录char tmp[1024];getcwd(tmp,sizeof(tmp));//getcwd()会将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,参数size为buf的空间大小。sprintf(cwd,"PWD=%s",tmp); //打印到字符串中putenv(cwd);//putenv 函数会将c wd 直接填写到环境表中
}// 什么叫做内键命令: 内建命令就是bash自己执行的,类似于自己内部的一个函数!
// 1->yes, 0->no, -1->err
int doBuildin(char* argv[])
{if(strcmp(argv[0],"cd") == 0) //cd ...{char *path =  NULL;if(argv[1] == NULL) path = homepath();else path = argv[1];cd(path);return 1;}else if(strcmp(argv[0],"export") == 0){if(argv[1] == NULL) return 1;strcpy(enval,argv[1]);putenv(enval);return 1;}return 0;
}int execute(char *argv[])
{pid_t id = fork();if(id < 0) return -1;else if(id == 0) //child{//exec commandexecvp(argv[0],argv);//execvp()会从环境变量所指的目录中查找符合参数 file 的文件名, 找到后执行该文件, 然后将第二个参数argv 传给该执行的文件。exit(1);}else //father{int status = 0;pid_t res = waitpid(-1, &status, 0);//阻塞式等待if(res > 0)//等待成功{printf("exit code: %d \n", WEXITSTATUS(status));}}return 0;
}int main()
{while(1){char usercommand[NUM];//存储命令char *argv[SIZE];//存储命令拆分后结果//1.打印提示符 && 获取用户命令字符串int n = getUserCommand(usercommand,sizeof(usercommand));if(n <= 0) continue;//输入空也可以重新输入//2.分割字符串//"ls -a -l" ---> "ls" "-a" "-l"commandSplit(usercommand,argv);//3.check buildin command 检查内键命令n = doBuildin(argv);if(n) continue;//4.执行命令execute(argv);}
}

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

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

相关文章

loadrunner lr解决参数化一次取多条记录【一对多问题】

场景&#xff1a;批量进行工作汇报&#xff0c;一个项目下选择三个工作项进行汇报&#xff1b; 问题&#xff1a;项目GUID变化一次&#xff0c;工作项GUID要取三个值&#xff0c;也就是变化三次&#xff1b; 我们知道&#xff0c;在Parameter List中可以设置参数取值规则&…

Tomcat(二) 动静分离

一、(TomcatNginx)动静分离 1、单机反向代理 利用 nginx 反向代理实现全部转发至指定同一个虚拟主机 客户端curl www.a.com 访问nginx服务&#xff0c;nginx服务通过配置反向代理proxy_pass www.a.com:8080&#xff0c;最终客户端看到的是www.a.com 实验中&#xff1a;7-3 做客…

#QT(智能家居界面-界面切换)

1.IDE&#xff1a;QTCreator 2.实验 3.记录 &#xff08;1&#xff09;创建一个新界面&#xff08;UI界面&#xff09; &#xff08;2&#xff09;可以看到新加入一个ui文件&#xff0c;双击打开&#xff0c;设置窗口大小与登录界面一致 &#xff08;3&#xff09;加入几个PUS…

python 基础知识点(蓝桥杯python科目个人复习计划58)

今日复习内容&#xff1a;做题 例题1&#xff1a;仙境诅咒 问题描述&#xff1a; 在一片神秘的仙境中&#xff0c;有N位修仙者&#xff0c;他们各自在仙境中独立修炼&#xff0c;拥有他们独特的修炼之地和修炼之道&#xff0c;修炼者们彼此之间相互尊重&#xff0c;和平相处…

P-States/C-States/S-States/G-States/D-States

P-States是指处理器的性能状态&#xff0c;可以根据需要调整处理器的工作频率和电压来平衡性能和能效。 S-States是指系统的睡眠状态&#xff0c;可以让系统在空闲时进入低功耗状态以节省能量。 G-States是系统的全局状态&#xff0c;通常用于描述整个系统的运行状态。 C-St…

用ChatGPT计算植被归一化指数NDVI并出图的详细教程

用ChatGPT结合GIS计算植被归一化指数NDVI出图教程 用ENVI计算比较繁琐&#xff0c;如今AI的盛行&#xff0c;我们可以轻松解决计算问题&#xff0c;只需1一分钟变可以出图。 详细教学请看上方视频步骤。 更多ChatGPT教学内容请见&#xff1a;ChatGPT结合GIS&#xff1a;一分钟…

如何在Vue中进行单元测试?

前端开发中&#xff0c;单元测试是一个非常重要的环节&#xff0c;它可以帮助我们在开发过程中发现潜在的问题&#xff0c;并确保我们的代码在不断迭代的过程中依然能够保持稳定。在Vue中进行单元测试同样非常重要&#xff0c;本文将介绍如何在Vue项目中进行单元测试。 在Vue中…

Qt::TabWidget

在Tab的右上角添加控件 QPushButton *add new QPushButton; add->setText(""); add->resize(30,30); ui->tabWidget->setCornerWidget(add,Qt::TopRightCorner); 结果&#xff1a; Tab添加子页 QWidget*newp new QWidget; ui->tabWidget->add…

【脑切片图像分割】MATLAB 图像处理 源码

1. 简单图像处理 加载图像 Brain.jpg&#xff0c;使用直方图和颜色分割成区域这些区域有不同的颜色。 这是一个更高级的问题&#xff0c;有多个解决它的方法。 例如&#xff0c;您可以计算具有特定数字的图像的直方图&#xff08;例如 16 - 32&#xff09;&#xff0c;找到直方…

蜂窝物联:智慧生态茶园建设方案

一、项目背景 为了进一步提高茶产业集约化、产业化发展水平&#xff0c;充分运用物联网、互联网等高新技术为产业赋能&#xff0c;加速推动安溪茶产业转型升级&#xff0c;县政府决定在安溪县推进“安溪智慧生态茶园项目”&#xff0c;并以茶叶重镇感德镇实施“安溪智慧生态茶…

分享一本好书《大模型应用开发极简入门:基于GPT-4和ChatGPT》

如果问个问题&#xff1a;有哪些产品曾经创造了伟大的奇迹&#xff1f;ChatGPT 应该会当之无愧入选。仅仅发布 5 天&#xff0c;ChatGPT 就吸引了 100 万用户——当然&#xff0c;数据不是关键&#xff0c;关键是其背后的技术开启了新的 AI 狂潮&#xff0c;成为技术变革的点火…

Python知识汇总

重要链接&#xff1a; matplotlib库&#xff1a;matplotlib — Matplotlib 3.5.1 documentation DataFrame库&#xff1a;DataFrame — pandas 2.2.1 documentation (pydata.org) Python Matplotlib 实现散点图、曲线图、箱状图、柱状图示例&#xff1a;Python Matplotlib 实…

深度学习预测分析API:金融领域的Game Changer

&#x1f680; 引言 在这个AI遍地开花的时代&#xff0c;谁能成为金融领域的真正Game Changer&#xff1f;那必然是是深度学习预测分析API。如大脑般高效运转的系统不仅颠覆了传统操作&#xff0c;更是以无与伦比的速度和精度赋予了金融数据以全新的生命。 &#x1f4bc; 广泛…

uniapp制作--进步器的选择

介绍&#xff1a; 进步器的选择,一般用于商城购物选择物品数量的场景 注意&#xff1a;该输入框只能输入大于或等于0的整数 效果展示&#xff1a; 代码展示&#xff1a; 以下是一个简单的购物车页面示例&#xff0c;包括选择商品和显示数量的功能&#xff1a; 在这个示例中…

探索人工智能的关键术语与方法

目录 前言1 机器学习&#xff08;Machine Learning&#xff09;2 数据科学&#xff08;Data Science&#xff09;3 监督学习&#xff08;Supervised Learning&#xff09;4 无监督学习&#xff08;Unsupervised Learning&#xff09;5 深度学习&#xff08;Deep Learning&#…

紫光展锐T618_4G安卓核心板方案定制

紫光展锐T618核心板是一款采用纯国产化方案的高性能产品&#xff0c;搭载了开放的智能Android操作系统&#xff0c;并集成了4G网络&#xff0c;支持2.5G5G双频WIFI、蓝牙近距离无线传输技术以及GNSS无线定位技术。 展锐T618核心板应用旗舰级 DynamlQ架构 12nm 制程工艺&#x…

私有化部署自己的ChatGPT,免费开源的chatgpt-next-web搭建

随着AI的应用变广&#xff0c;各类AI程序已逐渐普及&#xff0c;尤其是在一些日常办公、学习等与撰写/翻译文稿密切相关的场景&#xff0c;大家都希望找到一个适合自己的稳定可靠的ChatGPT软件来使用。 ChatGPT-Next-Web就是一个很好的选择。它是一个Github上超人气的免费开源…

简单介绍一下Qt动画系统,并举例说明如何使用

目录 Qt动画系统介绍 分类举例说明 1. 属性动画&#xff08;Property Animation&#xff09;&#xff1a; 2. 并行动画&#xff08;Parallel Animation&#xff09;&#xff1a; 3. 顺序动画&#xff08;Sequential Animation&#xff09;&#xff1a; 4. 动画组&#xf…

闯入监测报警摄像机

闯入监测报警摄像机是用于监测和报警未经授权者闯入特定区域的安全设备。该摄像机通常设置在建筑物、仓库、办公室等需要保护的场所&#xff0c;用于监控周围环境并及时警示相关人员。闯入监测报警摄像机是一种集视频监控和报警功能于一体的安全设备&#xff0c;旨在防范和监测…

2024/3/5打卡线性DP问题---数字三角形*

线性DP&#xff1a; 所谓线性DP&#xff0c;是指递推方程有一种明显的线性关系存在。 在状态规划中&#xff0c;状态可以是一维的&#xff0c;二维的&#xff0c;多维的。例如&#xff0c;在背包问题中&#xff0c;就是一个二维的状态&#xff0c;在求解状态的时候&#xff0c;…