从零写OS(十三):Shell,把所有东西串起来

前十二章,内核从一个 512 字节的 Bootloader 长成了有进程调度、文件系统、VFS 的微型系统。但用户还没有办法和它交互。 这一章做 Shell——一个可以敲命令操作文件的命令行。 先把概念搞清楚 Shell 是普通进程 Shell 不是内核的一部分。它是一个运行在用户态的普通进程,通过系统调用和内核打交道,和 ls、cat 这些程序的地位完全一样。 真实系统里,Shell 用 fork + exec 启动外部命令。我们这里简化:四条命令直接内嵌在 Shell 进程里,不做 fork/exec。 tokenize:命令行的第一步 用户输入一行字符串,Shell 要把它拆成命令名和参数: "write hello.txt world" ↓ tokenize argv[0] = "write" argv[1] = "hello.txt" argv[2] = "world" 做法是遍历字符串,遇到空格就写入 \0 截断,记录每段的起始地址。不需要任何库函数,20 行搞定。 串口 I/O 键盘输入通过串口读取(x86 端口 0x3F8)。QEMU 的 -serial mon:stdio 把宿主机终端直接映射到串口,你在终端敲的每个字符都会被 in 指令读到。 实现了什么 四条命令: 命令 功能 write <文件> <内容> 创建文件并写入内容 read <文件> 读取文件内容并打印 ls 列出根目录所有文件 help 打印帮助 关键代码 readline:读一行,支持 backspace static int readline(char *buf, int maxlen) { int i = 0; while (i < maxlen - 1) { char c = serial_getchar(); if (c == '\r' || c == '\n') { serial_print("\r\n"); break; } if (c == 127 || c == '\b') { if (i > 0) { i--; serial_print("\b \b"); } continue; } buf[i++] = c; char echo[2] = {c, 0}; serial_print(echo); // 回显给用户 } buf[i] = '\0'; return i; } \b \b 是终端删除字符的标准做法:退格、打空格覆盖、再退格。 ...

May 6, 2026 · 2 min · 大飞
京ICP备14031575号-3