Linux实现简易shell

在这里插入图片描述

文章目录

    • 🦄0. shell
    • 🐮1. 交互及获取命令行
    • 🐷2. 解析命令行
    • 🐯3. 执行命令行
      • 🐅3.1 普通命令
      • 🐅3.2 内建命令
    • 🦁4. 主函数逻辑及演示

本章代码gitee仓库:简易shell

🦄0. shell

shell是操作系统外的一层外壳程序,负责将用户的指令执行,将指令获取到之后再交给操作系统,操作系统将指令执行完毕之后的结果通过shell交给用户。shell/bash也是一个进程,本质上也是通过创建子进程来执行这些指令。

🐮1. 交互及获取命令行

我们先来开一下交互及我们输入的命令行格式

image-20231103220238498

先来做交互的页面,这其实就是一个while循环,一直等着我们输入指令,我们可以通过获取环境变量来获取这些信息。

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
const char *getUserName()
{return getenv("USER");
}
const char *getHostName()
{return getenv("HOSTNAME");
}
void getPwd()
{getcwd(pwd,sizeof(pwd));
}
void interact(char *cline, int size)
{getPwd();printf(LEFT"%s@%s %s"RIGHT""LABLE" ",getUserName(),getHostName(),pwd);char *s = fgets(cline,size,stdin);	//获取指令assert(s);(void)s;  //防止后面不使用s变量报警告,假装用一下cline[strlen(cline)-1] = '\0';  //将回车抵消//printf("%s\n",s);
}

我们可以输出我们获取的命令测试一下

image-20231103221103250

🐷2. 解析命令行

获取到命令之后,我们就要解析这个命令,这个解析的本质上,就是将获取的字符串进行分割,分割各个部分:要执行的命令所带的命令行参数

例如ls -a -l,我们就需要解析成:

  • 所需执行的命令:ls
  • 命令行参数:-a-l
#define DELIM " \t"
int splitString(char cline[], char *_argv[])
{int i = 0;_argv[i++] = strtok(cline,DELIM);while(_argv[i++] = strtok(NULL,DELIM));return i-1;
}

image-20231103221728909

🐯3. 执行命令行

获取到所需执行的命令和参数之后,其实就是创建子进程,然后程序替换来执行这个命令,但是这些命令分为普通命令和内建命令:

  • 普通命令:创建子进程直接程序替换
  • 内建命令:父进程自己执行

🐅3.1 普通命令

这里没有什么高科技,就是简单的创建子进程、程序替换和进程等待

#define EXIT_CODE 11
void normalExcute(char *_argv[])
{pid_t id = fork();if(id < 0){perror("fork fail");return; }else if(id == 0){//子进程执行命令//execvpe(_argv[0],_argv,environ);  //直接程序替换execvp(_argv[0],_argv);   //直接替换程序exit(EXIT_CODE);  //替换失败的退出码}else{//父进程等待子进程退出int status = 0;pid_t rid = waitpid(id,&status,0);  //阻塞等待if(rid == id){lastcode = WEXITSTATUS(status);}}
}

🐅3.2 内建命令

对应内建命令,需要我们自己去一个一个添加然后判断,这里做一个简单的演示

int buildCommand(char *_argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0],"cd") == 0){chdir(_argv[1]);getPwd();sprintf(getenv("PWD"),pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0],"export") == 0) //导环境变量{putenv((char*)_argv[1]);return 1;}else if(_argc == 2 && strcmp(_argv[0],"echo") == 0)                                 {if(strcmp(_argv[1],"$?")==0){printf("%d\n",lastcode);lastcode = 0;}else if(*_argv[1] == '$'){char*val = getenv(_argv[1]+1);if(val) printf("%s\n",val);}else  printf("%s\n",_argv[1]);return 1;}//将ls命令显示颜色if(strcmp(_argv[0],"ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}

🦁4. 主函数逻辑及演示

这里我们全部都封装起来了,各个模块解耦,想要修改的话,也很方便,完整的代码可以去仓库里面查看。

#define LINE_SIZE 1024
#define ARGC_SIZE 32int main()
{while(!quit){//交互 获取命令行interact(commandline,sizeof(commandline));//解析命令行int argc = splitString(commandline,argv);if(argc == 0) continue;//for(int i=0;argv[i];i++) printf("%s\n",argv[i]);//printf("%s\n",argv);//普通命令执行int flag = buildCommand(argv,argc);if(!flag) normalExcute(argv);}return 0;
}

GIF 2023-11-3 22-37-06
所以我们每次登录的时候,界面会显示这些信息,其实就是因为系统启动了一个shell进程。

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

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

相关文章

K8S知识点(二)

&#xff08;1&#xff09;K8S概念 K8S是通过控制pod来控制容器进而控制程序的 service是沟通Pod和外键的桥梁&#xff0c;可以实现负载均衡的效果&#xff0c;加权负载的效果 &#xff08;2&#xff09;环境搭建-环境规划 &#xff08;3&#xff09;环境搭建-主机安装 使用…

C++ 代码实例:并查集简单创建工具

文章目录 前言代码仓库代码说明main.cppMakefile 结果总结参考资料作者的话 前言 C 代码实例&#xff1a;并查集简单创建工具。 代码仓库 yezhening/Programming-examples: 编程实例 (github.com)Programming-examples: 编程实例 (gitee.com) 代码 说明 简单地创建并查集注…

<Vue>使用依赖注入的方式共享数据

什么是vue依赖注入&#xff1f; Vue是一个用于构建用户界面的渐进式框架。 它提供了一种简单而灵活的方式来管理组件之间的数据流&#xff0c;即依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;。 依赖注入是一种设计模式&#xff0c;它允许一个组件从另一…

HTTPS的加密方式超详细解读

在了解https的加密方式之前&#xff0c;我们需要先行了解两个特别经典的传统加密方式&#xff1a; 1、对称加密 1.1、定义 需要对加密和解密使用相同密钥的加密算法。所谓对称&#xff0c;就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解…

【技术干货】开源库 Com.Gitusme.Net.Extensiones.Core 的使用

目录 1、项目介绍 2、为项目添加依赖 3、代码中导入命名空间 4、代码中使用 示例 1&#xff1a;string转换 示例 2&#xff1a;object转换 1、项目介绍 Com.Gitusme.Net.Extensiones.Core是一个.Net扩展库。当前最新版本1.0.4&#xff0c;提供了常见类型转换&#xff0c…

<蓝桥杯软件赛>零基础备赛20周--第4周--杂题-1

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周&#xff08;读者可以按…

统计学习方法 条件随机场

文章目录 统计学习方法 条件随机场随机场马尔可夫随机场定义因子分解 条件随机场定义参数化形式简化形式矩阵形式 概率预测问题前向-后向算法概率的计算期望值的计算 学习问题改进的迭代尺度法拟牛顿法 解码问题 统计学习方法 条件随机场 学习李航的《统计学习方法》时&#x…

ok-解决qt5发布版本,直接运行exe缺少各种库的问题

已实验第二种方法可用。 工具&#xff1a;电脑必备、QT下的windeployqt Qt 官方开发环境使用的动态链接库方式&#xff0c;在发布生成的exe程序时&#xff0c;需要复制一大堆 dll&#xff0c;如果自己去复制dll&#xff0c;很可能丢三落四&#xff0c;导致exe在别的电脑里无法…

C++11 智能指针学习笔记

非常棒的学习博客 在C中没有垃圾回收机制&#xff0c;必须自己释放分配的内存&#xff0c;否则就会造成内存泄露。 1. shared_ptr 共享智能指针是指多个智能指针可以同时管理同一块有效的内存&#xff0c;共享智能指针 shared_ptr 是一个模板类。智能指针的核心实现技术是引用…

Framebuffer 介绍和应用编程

前言&#xff1a; 使用的开发板为韦东山老师的 IMX6ULL 目录 Framebuffer介绍 LCD 操作原理 涉及的 API 函数 1.open 函数 2.ioctl 函数 3.mmap 函数 Framebuffer 程序分析 1.打开设备 2.获取 LCD 参数 3.映射 Framebuffer 4.描点函数 5.随便画几个点 6.上机实验…

[vmware]vmware虚拟机压缩空间清理空间

vmware中的ubuntu使用如果拷贝文件进去在删除&#xff0c;vmare镜像文件并不会减少日积月累会不断是的真实物理磁盘空间大幅度减少&#xff0c;比如我以前windows操作系统本来只有30GB最后居然占道硬盘200GB&#xff0c;清理方法有2种。 第一种&#xff1a;vmware界面操作 第二…

Lamport Clock算法

Lamport Clock 是一种表达逻辑时间的逻辑时钟&#xff08;logical clock&#xff09;&#xff0c;能够计算得到历史事件的时间偏序关系。 假设 P0进程是分布式集群中心节点中的监控者&#xff0c;用于统一管理分布式系统中事件的顺序。其他进程在发送消息之前和接受事件消息之后…