当前位置: 首页 > news >正文

从0开始的操作系统手搓教程43——实现一个简单的shell

目录

添加 read 系统调用,获取键盘输入 :sys_read

putchar和clear

上班:实现一个简单的shell

测试上电


我们下面来实现一个简单的shell

添加 read 系统调用,获取键盘输入 :sys_read

/* Read count bytes from the file pointed to by file descriptor fd into buf,* return the number of bytes read on success, return -1 if end of file is* reached*/
int32_t sys_read(int32_t fd, void *buf, uint32_t count)
{KERNEL_ASSERT(buf);int32_t ret = -1;uint32_t global_fd = 0;if (fd < 0 || fd == stdout_no || fd == stderr_no){ccos_printk("sys_read: fd error\n");}else if (fd == stdin_no){char *buffer = buf;uint32_t bytes_read = 0;while (bytes_read < count){*buffer = ioq_getchar(&keyboard_ringbuffer);bytes_read++;buffer++;}ret = (bytes_read == 0 ? -1 : (int32_t)bytes_read);}else{global_fd = fd_local2global(fd);ret = file_read(&file_table[global_fd], buf, count);}return ret;
}

我们终于跟老朋友见面了。我们修订一下:sys_read,现在实现了读取文件的功能。它首先检查传入的 buf 指针是否有效。如果文件描述符 fd 无效(例如小于0或者是标准输出、标准错误),则会打印错误信息。如果文件描述符是标准输入(stdin_no),函数会从键盘输入的缓冲区 keyboard_ringbuffer 中读取字符,将其存入 buf 中,直到读取指定的字节数或达到文件末尾。函数会返回成功读取的字节数,如果没有读取到任何数据,返回 -1。如果文件描述符不是标准输入,函数会根据 fd 获取对应的文件,并调用 file_read 函数来执行实际的读取操作,并返回成功读取的字节数。如果文件读取失败,返回 -1

int32_t read(int32_t fd, void *buf, uint32_t count)
{return _syscall3(SYS_READ, fd, buf, count);
}

putchar和clear

这个把我们之前做的工作编程系统调用即可

/* Outputs a character */
void putchar(char char_asci) {_syscall1(SYS_PUTCHAR, char_asci);
}
/* Clears the screen */
void clear(void) {_syscall0(SYS_CLEAR);
}
​
void sys_putchar(char char_asci)
{console__ccos_putchar(char_asci);
}
​
​
/* Initialize the system call table */
void syscall_init(void) {verbose_ccputs("syscall_init start\n"); // Logging the start of syscall initialization/* Set the system call table entries for various system call numbers */syscall_table[SYS_GETPID] = sys_getpid; // Get process IDsyscall_table[SYS_WRITE] = sys_write;   // Write to consolesyscall_table[SYS_MALLOC] = sys_malloc; // Memory allocationsyscall_table[SYS_FREE] = sys_free;     // Free allocated memorysyscall_table[SYS_FORK] = sys_fork;     // Fork a new processsyscall_table[SYS_READ] = sys_read;syscall_table[SYS_PUTCHAR] = sys_putchar;syscall_table[SYS_CLEAR] = clean_screen;verbose_ccputs("syscall_init done\n"); // Logging the completion of syscall// initialization
}

上班:实现一个简单的shell

#include "include/user/ccshell/ccshell.h"
#include "include/defines.h"
#include "include/filesystem/file.h"
#include "include/library/string.h"
#include "include/library/types.h"
#include "include/syscall/syscall.h"
#include "include/user/stdio/stdio.h"
#include "include/filesystem/filesystem_settings.h"
#include "include/user/library/user_assertion.h"
#define CMD_LEN MAX_PATH_LEN
#define MAX_ARG_NR (16)
​
/* Stores the input command */
static char cmd_line[CMD_LEN] = {0};
​
/* Used to record the current directory; it is updated every time the cd command* is executed */
char cwd_cache[MAX_PATH_LEN] = {0};
​
/* Outputs the shell prompt */
void print_prompt(void)
{printf("[" HOST_NAME "@localhost %s]$ ", cwd_cache);
}
​
/* Reads up to 'count' bytes from the keyboard buffer into 'buf' */
static void readline(char *buf, int32_t count)
{user_assert(buf && count > 0);char *pos = buf;
​while (read(stdin_no, pos, 1) != -1 &&(pos - buf) < count){ // Read until enter key is foundswitch (*pos){/* If enter or newline is found, treat it as the end of the command*/case '\n':case '\r':*pos = 0; // Add null terminator to cmd_lineputchar('\n');return;
​case '\b':if (cmd_line[0] != '\b'){          // Prevent deleting non-inputted data--pos; // Move back to the previous character in the bufferputchar('\b');}break;
​/* For other characters, output normally */default:putchar(*pos);pos++;}}printf("readline: can't find enter_key in the cmd_line, max num of char is ""128\n");
}

先说说readline:这段代码实现了一个从键盘缓冲区读取用户输入的功能。函数readline的作用是从输入流中读取字符,直到遇到回车键(\n\r)为止,或者读取达到指定的字节数限制。读取的内容会存储到buf中。具体步骤如下:

  1. 函数首先检查传入的缓冲区指针buf是否有效,并确认count大于0。

  2. while循环会持续读取一个字符(通过read(stdin_no, pos, 1)),直到读取到回车键或达到指定的字符数量(count)。读取的字符会存储在buf中。

  3. 当遇到回车符(\n\r)时,表示用户输入完成,此时将当前位置字符设置为'\0',并输出换行符,表示命令输入结束。

  4. 如果遇到退格符(\b),程序会检查输入内容是否为空。如果不为空,指针会退回一个字符,删除命令行中的最后一个字符,并输出退格符。此功能允许用户删除输入的字符。

  5. 其他字符直接输出并追加到pos指向的位置,继续读取下一个字符。

  6. 如果没有在指定字符数内读取到回车键,则会输出错误提示,表明命令行输入超出了最大字符限制。

这个函数的设计使得用户可以在命令行中输入命令,且支持基本的退格功能,直到按下回车键为止。

ccshell是我们的核心:

void ccshell(void)
{cwd_cache[0] = '/';while (1){print_prompt();k_memset(cmd_line, 0, CMD_LEN);readline(cmd_line, CMD_LEN);if (cmd_line[0] == 0){continue;}}user_panic("Man!: you should not be here!!!");
}

这段代码实现了一个简单的命令行shell功能。函数ccshell定义了一个无限循环,其中每次循环都会显示提示符,等待用户输入命令。命令输入通过readline函数完成,读取用户输入并存储到cmd_line中。每次读取命令之前,cmd_line会被清空,确保新命令不会受到旧命令的影响。如果用户没有输入命令,程序会跳过本次循环。当用户输入命令时,如果命令不为空,程序会继续执行。虽然代码没有明确的退出机制,但如果程序异常执行到user_panic("Man!: you should not be here!!!"),说明发生了错误。

测试上电

#include "include/device/console_tty.h"
#include "include/kernel/init.h"
#include "include/library/kernel_assert.h"
#include "include/thread/thread.h"
#include "include/user/stdio/stdio.h"
#include "include/memory/memory.h"
#include "include/library/ccos_print.h"
#include "include/filesystem/filesystem.h"
#include "include/library/string.h"
#include "include/filesystem/dir.h"
#include "include/syscall/syscall.h"
#include "include/user/ccshell/ccshell.h"
void init(void);
​
int main(void)
{init_all();while(1);
}
​
// init process here
void init(void)
{uint32_t ret_pid = fork();if (ret_pid){while(1);}else{ccshell();}while (1);
}
​

注意多敲几下键盘,因为输出非常多。

下一篇

从0开始的操作系统手搓教程44——实现更好的shell-CSDN博客文章浏览阅读766次,点赞14次,收藏9次。在 Linux 系统中,快捷键如“Ctrl+u”和“Ctrl+l”是由操作系统提供的标准功能,但它们的实现方式并不是直接由键盘驱动程序(keyboard.c)来处理的。如果在键盘驱动程序中加入过多的逻辑处理,会导致系统的中断处理变得非常复杂,效率降低,进而影响整个系统的响应速度。的数据类型(从16位改为32位),因为一旦改动数据类型,后续代码可能会受到影响,造成所谓的“雪崩效应”,即需要改动很多地方的代码和解释。时,输入缓冲区中的字符会被清除,屏幕会被清空,然后打印命令提示符,再显示用户已输入的命令。 https://blog.csdn.net/charlie114514191/article/details/146144528

相关文章:

从0开始的操作系统手搓教程43——实现一个简单的shell

目录 添加 read 系统调用&#xff0c;获取键盘输入 :sys_read putchar和clear 上班&#xff1a;实现一个简单的shell 测试上电 我们下面来实现一个简单的shell 添加 read 系统调用&#xff0c;获取键盘输入 :sys_read /* Read count bytes from the file pointed to by fi…...

‌Visual Studio Code(VS Code)支持的编程语言

‌JavaScript‌&#xff1a;VS Code 原生支持 JavaScript&#xff0c;提供语法高亮、代码折叠、自动补全等功能。推荐使用ESLint和Prettier进行代码格式化和错误检查‌。 ‌TypeScript‌&#xff1a;作为 JavaScript 的超集&#xff0c;TypeScript 在 VS Code 中也得到原生支持…...

探索AI对冲基金:开源自动化交易系统的革新之路

在量化交易领域,人工智能技术的应用正悄然改变传统对冲基金的运作模式。GitHub上的开源项目ai-hedge-fund为开发者和金融从业者提供了一个独特的实践平台。该项目通过多智能体系统架构,整合市场数据分析、量化策略生成、风险管理和投资组合优化等核心功能,实现了从数据采集到…...

C语言每日一练——day_3(快速上手C语言)

引言 针对初学者&#xff0c;每日练习几个题&#xff0c;快速上手C语言。第三天。&#xff08;会连续更新&#xff09; 采用在线OJ的形式 什么是在线OJ&#xff1f; 在线判题系统&#xff08;英语&#xff1a;Online Judge&#xff0c;缩写OJ&#xff09;是一种在编程竞赛中用…...

vue3中接收props的两种写法

在 Vue 3 中&#xff0c;接收 props 有两种主要的写法&#xff0c;分别是运行时声明和基于类型的声明。下面为你详细介绍这两种写法。 1. 运行时声明 运行时声明是 Vue 2 中就已经存在的方式&#xff0c;在 Vue 3 中依然可以使用。这种方式通过在组件中使用 defineProps 宏来…...

Django下防御Race Condition

目录 漏洞原因 环境搭建 复现 A.无锁无事务时的竞争攻击 B.无锁有事务时的竞争攻击 防御 A.悲观锁加事务防御 B.乐观锁加事务防御 总结 漏洞原因 Race Condition 发生在多个执行实体&#xff08;如线程、进程&#xff09;同时访问共享资源时&#xff0c;由于执行顺序…...

Vue 项目中,.env文件怎么用?

在 Vue 项目中&#xff0c;.env 文件用于存储环境变量&#xff0c;不同的环境&#xff08;如开发环境、测试环境、生产环境&#xff09;可以使用不同的 .env 文件来管理对应的配置信息。以下是关于 Vue 项目中 .env 文件的详细使用方法&#xff1a; 1. 项目创建 确保你已经使…...

LeetCode hot 100—爬楼梯

题目 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例…...

【js逆向】

地址&#xff1a;aHR0cHM6Ly93d3cud2VpYm90b3AuY24vMi4wLw f12进入 debugger&#xff0c;过debugger 查看预览数据 全局搜索 请求网址中的 api.weibotop.cn 在下方疑似找到了加密和解密的函数 断点调试 控制台输出 那个n就是 常见的 cryptoJs库 const cryptoJs require(cry…...

论文阅读-秦汉时期北方边疆组织的空间互动模式与直道的定位(中国)

论文英文题目&#xff1a;A spatial interaction model of Qin-Han Dynasty organisation on the northern frontier and the location of the Zhidao highway (China) 发表于&#xff1a;journal of archaeological science&#xff0c;影响因子&#xff1a;3.030 论文主要是…...

DirectX12(D3D12)基础教程四 入门指南

本章主要讲了些D3D12概念和理论&#xff0c;对第一、二章相关概念的补充和纠正&#xff0c;要的理解D3D12概念和理论基础&#xff0c;结合代码加深理解。 命令队列和命令列表 为了实现渲染工作的重用和多线程缩放&#xff0c; 在 D3D12 中&#xff0c;做了三个重要方面不同于 …...

C语言:确定进制

题目&#xff1a; 6942对于十进制来说是错误的&#xff0c;但是对于13进制来说是正确的。即, 6(13) 9(13) 42(13)&#xff0c; 而 42(13)4131213054(10)。 任务是写一段程序&#xff0c;读入三个整数p、q和 r&#xff0c;然后确定一个进制 B(2<B<40) 使得 p q r。 如果…...

如何在 Windows 10 启用卓越性能模式及不同电源计划对比

在使用 powercfg -duplicatescheme 命令启用 “卓越性能模式”&#xff08;即 Ultimate Performance 模式&#xff09;之前&#xff0c;有几个前提条件需要注意&#xff1a; 前提条件&#xff1a; 系统版本要求&#xff1a;卓越性能模式 仅在 Windows 10 专业版 或更高版本&a…...

Unity Android出包

Unity Android出包 1.Android Studio版本 不能高于Unity的版本 2.so库 这个库需要自己拷贝到Android工程当中 3.JDK版本太老 编译可以正常&#xff0c;但无法运行 File->ProjectStructure->SDK Location->Gradle Setting->Gradle JDK->X:/Android Stuido/jre …...

Day04 模拟原生开发app过程 Androidstudio+逍遥模拟器

1、用Androidstudio打开已经写好了的music项目 2、逍遥模拟器打开apk后缀文件 3、在源文件搜索关键字 以后的测试中做资产收集...

2025人工智能AI新突破:PINN内嵌物理神经网络火了

最近在淘金的时候发现基于物理信息的神经网络&#xff08;简称PINN&#xff09;也是个研究热点&#xff0c;遂研读了几篇经典论文&#xff0c;深觉这也是个好发论文的方向&#xff0c;所以火速整理了一些个人认为很值得一读的PINN论文和同学们分享。 为了方面同学们更好地理解…...

通义万相 2.1 携手蓝耘云平台:开启影视广告创意新纪元

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

【计算机网络】深入解析 HTTP 请求中的 header 类型:Cookie 的概念、特点和应用场景:登录和用户认证

网络原理— HTTP 请求“报头”(header) Cookie 是什么 HTTP报头中的Cookie&#xff0c;用大白话来说&#xff0c;就像你去餐厅吃饭时拿到的一张会员卡&#xff1a; 初次访问 (清除该网站的所有 Cookie 后重新访问该网站&#xff0c;效果相同)&#xff1a; 当你第一次访问一个网…...

LeetCode 解题思路 11(Hot 100)

解题思路&#xff1a; 若相等&#xff1a; 直接返回 true。若当前元素大于目标值&#xff1a; 由于列递增&#xff0c;当前列下方所有元素均大于目标值&#xff0c;故排除该列&#xff08;向左移动&#xff09;。若当前元素小于目标值&#xff1a; 由于行递增&#xff0c;当前…...

警惕AI神话破灭:深度解析大模型缺陷与禁用场景指南

摘要 当前AI大模型虽展现强大能力&#xff0c;但其本质缺陷可能引发系统性风险。本文从认知鸿沟、数据困境、伦理雷区、技术瓶颈四大维度剖析大模型局限性&#xff0c;揭示医疗诊断、法律决策等8类禁用场景&#xff0c;提出可信AI建设框架与用户防护策略。通过理论分析与实操案…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

Vue3 PC端 UI组件库我更推荐Naive UI

一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用&#xff0c;前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率&#xff0c;还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库&#xff08;Naive UI、Element …...

解析“道作为序位生成器”的核心原理

解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制&#xff0c;重点解析"道作为序位生成器"的核心原理与实现框架&#xff1a; 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...

写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里

写一个shell脚本&#xff0c;把局域网内&#xff0c;把能ping通的IP和不能ping通的IP分类&#xff0c;并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...