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

从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…...

【Spring】基础/体系结构/核心模块

概述&#xff1a; Spring 是另一个主流的 Java Web 开发框架&#xff0c;该框架是一个轻量级的应用框架。 Spring 是分层的 Java SE/EE full-stack 轻量级开源框架&#xff0c;以 IoC&#xff08;Inverse of Control&#xff0c;控制反转&#xff09;和 AOP&#xff08;Aspect…...

01 音视频知识学习(视频)

图像基础概念 ◼像素&#xff1a;像素是一个图片的基本单位&#xff0c;pix是英语单词picture的简写&#xff0c;加上英 语单词“元素element”&#xff0c;就得到了“pixel”&#xff0c;简称px&#xff0c;所以“像素”有“图像元素” 之意。 ◼ 分辨率&#xff1a;是指图像…...

vue3自定义hooks遇到的问题

问题 写了一个输入查询参数和url返回加载中状态、请求方法、接口返回列表的hooks&#xff0c;出现的结果是只有请求方法有效&#xff0c;加载状态无效&#xff0c;接口返回了数据&#xff0c;页面却不显示数据。 代码如下 只展示部分关键代码 import { ref, toRefs, toRef, o…...

用Python和Docker-py打造高效容器化应用管理利器

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着容器化技术的发展,Docker已成为现代化应用部署的核心工具。然而,手动管理容器在规模化场景下效率低下。本文深入探讨如何利用Python结…...

liunx磁盘挂载和jar启动命令

一、磁盘挂载 查看历史磁盘挂载命令&#xff1a;history | grep mount 查看所有挂载硬盘命令&#xff1a;mount 磁盘挂载命令&#xff1a;mount -t cifs -o usernamesh**,passwordP!ss**** //192.168.1.2/attachmentfilesShare2.2/pdfCert /home/nybzg/cnfai1/pdfCert 二、j…...

gbase8s rss集群通信流程

什么是rss RSS是一种将数据从主服务器复制到备服务器的方法 实例级别的复制 (所有启用日志记录功能的数据库) 基于逻辑日志的复制技术&#xff0c;需要传输大量的逻辑日志,数据库需启用日志模式 通过网络持续将数据复制到备节点 如果主服务器发生故障&#xff0c;那么备用服务…...

使用 OpenSSL 和 Python 实现 AES-256-CBC 加密与解密(安全密钥管理)

环境 OpenSSLPython 使用 OpenSSL 加密 1. 生成 AES 密钥和 IV 强烈推荐使用方法一&#xff08;Python secrets 模块&#xff09;&#xff0c;因为它更安全。 方法一: Python 的 secrets 模块&#xff08;安全方式&#xff09; 不要使用 OpenSSL 的 rand 命令直接生成密钥…...

1-001:MySQL的存储引擎有哪些?它们之间有什么区别?

MySQL 存储引擎 ├── InnoDB&#xff08;默认引擎&#xff09; │ ├── 事务支持&#xff1a;支持 ACID 和事务&#xff08;事务日志、回滚、崩溃恢复&#xff09; │ ├── 锁机制&#xff1a;支持行级锁&#xff0c;提高并发性能 │ ├── 外键支持&#xff1a;支持外键…...

持续集成与部署(CI/CD)实践指南:测试工程师的效率革命之路

一、引言 在当今快速发展的软件开发领域&#xff0c;效率和质量是至关重要的。随着软件项目的规模和复杂度不断增加&#xff0c;传统的开发和测试流程逐渐暴露出诸多问题&#xff0c;如开发周期长、集成困难、测试覆盖不足以及部署风险高等。持续集成&#xff08;Continuous I…...

C盘清理技巧分享:释放空间,提升电脑性能

目录 1. 引言 2. C盘空间不足的影响 3. C盘清理的必要性 4. C盘清理的具体技巧 4.1 删除临时文件 4.2 清理系统还原点 4.3 卸载不必要的程序 4.4 清理下载文件夹 4.5 移动大文件到其他盘 4.6 清理系统缓存 4.7 使用磁盘清理工具 4.8 清理Windows更新文件 4.9 禁用…...

如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统

我在业余时间开发了一款自己的独立产品&#xff1a;升讯威在线客服与营销系统。陆陆续续开发了几年&#xff0c;从一开始的偶有用户尝试&#xff0c;到如今线上环境和私有化部署均有了越来越多的稳定用户。 随时近来 AI 大模型的火热&#xff0c;越来越多的客户&#xff0c;问…...

能否调整爬虫以支持多页商品列表?

当然可以&#xff01;调整爬虫以支持多页商品列表是一个常见的需求&#xff0c;尤其是在商品数量较多时。通过分析目标网站的分页机制&#xff0c;可以实现自动翻页并获取多页商品列表。以下是如何调整爬虫代码以支持多页商品列表的详细步骤和代码示例。 一、分析分页机制 首…...

【AI智能体报告】开源AI助手的革命:OpenManus深度使用报告

一、引言&#xff1a;当开源智能体走进生活 2025年3月&#xff0c;MetaGPT团队用一场"开源闪电战"改写了AI Agent的竞争格局。面对商业产品Manus高达10万元的邀请码炒作&#xff0c;他们仅用3小时便推出开源替代品OpenManus&#xff0c;首日即登顶GitHub趋势榜。 …...

Python 逆向工程:2025 年能破解什么?

有没有想过在复杂的软件上扭转局面&#xff1f;到 2025 年&#xff0c;Python 逆向工程不仅仅是黑客的游戏&#xff0c;它是开发人员、安全专业人员和好奇心强的人解开编译代码背后秘密的强大方法。无论您是在剖析恶意软件、分析 Python 应用程序的工作原理&#xff0c;还是学习…...

自动同步多服务器下SQL脚本2.0

考虑到1.0的适用场景太过苛刻&#xff0c;一次只支持读取至多一个版本的脚本变化&#xff0c;想涉及多个脚本的连续读取就有困难&#xff0c;于是有了2.0。 该版本支持读取多个版本的sql脚本&#xff0c;并且如果某一脚本出现sql问题【如重复插入相同名称的字段】&#xff0c;…...

深度学习与大模型-张量

大家好&#xff01;今天我们来聊聊张量&#xff08;Tensor&#xff09;。别被这个词吓到&#xff0c;其实它没那么复杂。 什么是张量&#xff1f; 简单来说&#xff0c;张量就是一个多维数组。你可以把它看作是一个装数据的容器&#xff0c;数据的维度可以是一维、二维&#…...

DeepSeek+Maxkb+Ollama+Docker搭建一个AI问答系统

DeepSeekMaxkbOllamaDocker搭建一个AI问答系统 文章目录 DeepSeekMaxkbOllamaDocker搭建一个AI问答系统前言一、创建同一内网的网络二、拉取两个镜像三、启动Ollama以及调试Maxkb4.Maxkb创建一个应用并建立知识库5、应用效果总结 前言 我觉得只要是使用Docker技术&#xff0c;…...

江科大51单片机笔记【12】DS18B20温度传感器(上)

写在前言 此为博主自学江科大51单片机&#xff08;B站&#xff09;的笔记&#xff0c;方便后续重温知识 在后面的章节中&#xff0c;为了防止篇幅过长和易于查找&#xff0c;我把一个小节分成两部分来发&#xff0c;上章节主要是关于本节课的硬件介绍、电路图、原理图等理论…...

P8662 [蓝桥杯 2018 省 AB] 全球变暖--DFS

P8662 [蓝桥杯 2018 省 AB] 全球变暖--dfs 题目 解析讲下DFS代码 题目 解析 这道题的思路就是遍历所有岛屿&#xff0c;判断每一块陆地是否会沉没。对于这种图的遍历&#xff0c;我们首先应该想到DFS。 代码的注意思想就是&#xff0c;在主函数中遍历找出所有岛屿&#xff0c…...

【让POSTGRESQL支持MS SQLSERVER的 extension】 Babelfish for PostgreSQL介绍及源码安装

什么是 Babelfish for PostgreSQL? Babelfish for PostgreSQL(简称 Babelfish)是一个扩展(extension),使 PostgreSQL 兼容 Microsoft SQL Server(MSSQL),允许 MSSQL 客户端和应用程序直接连接到 PostgreSQL 数据库,而无需对 SQL 语法、T-SQL 存储过程、数据类型等进…...

Vue 侧边栏导航栏 el-menu单个item和多个item

在固钉的下面去写菜单导航栏。 <el-menu class"aside-menu" router :default-active"$route.path" :collapse"isCollapse" background-color"#131b27" text-color"#bfcbd9" active-text-color"#20a0ff" :defau…...

Unity Dots从入门到精通之 Prefab引用 转 实体引用

文章目录 前言安装 DOTS 包实体引用Authoring 前言 DOTS&#xff08;面向数据的技术堆栈&#xff09;是一套由 Unity 提供支持的技术&#xff0c;用于提供高性能游戏开发解决方案&#xff0c;特别适合需要处理大量数据的游戏&#xff0c;例如大型开放世界游戏。 本文讲解我在…...

无人机避障——XTDrone中运行VINS-Fusion+Ego-planner进行路径规划

本文聚焦于无人机避障技术领域的经典方案&#xff0c;重点探讨视觉双目VINS-Fusion建图与Ego-planner路径规划的组合应用。通过视觉双目VINS-Fusion实现精准的环境建图与自身定位&#xff0c;结合Ego-planner的高效路径规划能力&#xff0c;使无人机在复杂环境中实现自主避障飞…...

【沐渥科技】氮气柜日常如何维护?

氮气柜的维护是确保其长期稳定运行、延长使用寿命和保持环境控制精度的关键。以下是沐渥氮气柜的日常维护和定期保养指南&#xff1a; 一、日常维护 柜体清洁 定期用软布擦拭柜体表面和内部&#xff0c;避免灰尘堆积。避免使用腐蚀性清洁剂&#xff0c;防止损伤密封条或传感器。…...

MATLAB 控制系统设计与仿真 - 24

PID 控制器分析- 控制器的形式 连续控制器的结构&#xff1a; 为滤波时间常数&#xff0c;这类PID控制器在MATLAB系统控制工具箱称为并联PID控制器&#xff0c;可由MATLAB提供的pid函数直接输入&#xff0c;格式为&#xff1a; 其他类型的控制器也可以由该函数直接输入&#x…...

C# Excel开源操作库MiniExcel使用教程

简介 MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。 目前主流框架大多需要将数据全载入到内存方便操作&#xff0c;但这会导致内存消耗问题&#xff0c;MiniExcel 尝试以 Stream 角度写底层算法逻辑&#xff0c;能让原本1000多MB占用降低到几MB&#xff0…...

linux(权限)

sudo 主要用来短暂的提权 权限 就是 >角色目标属性 这里面的角色就是---拥有者----所属组----other 所属组的目的&#xff1f; 更细化的管理 chmod 就是修改权限制 我们要是想要切换到体育的账号&#xff0c;我们可以去看一下有几个账号,我…...

paimon---同步mysql数据到paimon表中

1.1、mysql源表 CREATE TABLE mysql_orders (order_id varchar(100) NOT NULL,user_id varchar(100) DEFAULT NULL,amount decimal(10,2) DEFAULT NULL,update_time timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),PRIMARY KEY (order_i…...

《OpenCV》—— dlib(换脸操作)

文章目录 dlib换脸介绍仿射变换在 dlib 换脸中的应用 换脸操作 dlib换脸介绍 dlib 换脸是基于 dlib 库实现的一种人脸替换技术&#xff0c;以下是关于它的详细介绍&#xff1a; 原理 人脸检测&#xff1a;dlib 库中包含先进的人脸检测器&#xff0c;如基于 HOG&#xff08;方向…...