Linux 环境下基于 C/C++ 的模拟命令解释器
通过 C++ 与 POSIX API,重新实现目录浏览、文件复制、递归查找等 12 项 Linux 命令核心行为,理解命令背后的文件系统与系统接口。
把常见命令拆成可验证的系统接口调用。
01 / 项目快照
独立开发者
操作系统实践
Linux · VMware
C++ · Linux C / POSIX APIs
12 项模拟命令
文件系统 · 目录流 · 文件描述符 · 文件树遍历
02 / 项目目标
理解 Linux 命令背后的系统调用。
这不是完整 POSIX shell,也不是通过 system() 调用 ls 或 cp 的封装。报告中的 C++ 实现直接调用 Linux / POSIX C 函数库,重新实现目录浏览、目录切换、文件复制、递归查找等命令的核心行为。
03 / 命令实现
12 项命令,逐个拆分实现。
课程报告记录了 10 项基础命令和 2 项扩展命令,最终实现共 12 项功能。
mypwd显示当前工作目录
getcwd()mylist列出目录内容
opendir() · readdir() · closedir()mycd切换当前目录
chdir()mymkdir新建目录
mkdir()myrmdir删除目录
rmdir()mycp复制文件的核心行为
open() · read() · write()myrename重命名文件或目录
rename()myfind递归查找文件
ftw()mydate显示当前系统时间
time() · ctime()mycreate创建并写入文本文件
ofstreammydelete删除文本文件
remove()exit退出解释器
—04 / 系统如何工作
输入命令,分发函数,操作文件系统。
每个命令先被拆成独立函数,再调用对应的目录、文件或文件树接口。这种分解让复杂任务可以逐项理解、实现和手动验证。
05 / 目录流操作
不是执行 ls,而是直接遍历目录流。
mylist() 用 opendir() 打开指定目录并取得 DIR*,用 readdir() 逐个读取 struct dirent 节点,最后通过 closedir() 释放目录流。
DIR* d = opendir(dir.c_str());
if (d == NULL) return false;
struct dirent *dirent;
while (dirent = readdir(d)) {
cout << dirent->d_name;
}
closedir(d);06 / 文件描述符与复制
open → read → write。
mycopy() 使用整型文件描述符和 char buf[1024] 读取源文件并写入目标文件。报告中的实现还处理了目标已存在的情况:先询问是否覆盖;若不覆盖,则为新文件名追加 (1)。
fo1 = open(existname.c_str(), O_RDONLY);
fo2 = open(newname.c_str(), O_WRONLY | O_CREAT, S_IRWXU);
int size = read(fo1, buf, sizeof(buf));
write(fo2, buf, size);
close(fo1);
close(fo2);07 / 递归文件搜索
沿文件树逐层查找目标文件。
myfind() 调用 ftw() 递归遍历指定目录及其子目录。每到一个节点,ftw() 将路径、stat 信息和节点类型交给 callback fn();fn() 对比目标文件名并输出匹配路径。
int fn(const char *fpath, const struct stat *st, int typeflag) {
// compare the path tail with the target filename
if (typeflag == FTW_F) cout << fpath;
return 0;
}
ftw(dir, fn, depth);08 / 核心系统接口
getcwd · opendir · readdir · closedir · chdir · mkdir · rmdir
open · read · write · close · remove · rename
ftw · stat · dirent
time · ctime
09 / 实现证据
用原始代码说明实现,而不是制造截图。
原报告没有可公开的终端或 VMware 运行截图。因此此处只保留报告中可以核实的核心代码与说明,作为实现证据。
目录列出
DIR* d = opendir(dir.c_str());
if (d == NULL) return false;
struct dirent *dirent;
while (dirent = readdir(d)) {
cout << dirent->d_name;
}
closedir(d);mylist() 直接打开目录流、逐个读取 dirent 节点,再关闭目录流;它不是执行 ls 的封装。
目录切换
bool mycd(string path) {
if (chdir(path.c_str()) == 0) {
return true;
}
return false;
}mycd() 通过 chdir() 改变当前工作目录,并以返回值表达切换是否成功。
文件复制
fo1 = open(existname.c_str(), O_RDONLY);
fo2 = open(newname.c_str(), O_WRONLY | O_CREAT, S_IRWXU);
int size = read(fo1, buf, sizeof(buf));
write(fo2, buf, size);
close(fo1);
close(fo2);mycopy() 使用文件描述符和 1024-byte buffer 实现 open → read → write。目标已存在时,报告中的实现会询问是否覆盖;不覆盖则在新文件名后追加 (1)。
递归查找
int fn(const char *fpath, const struct stat *st, int typeflag) {
// compare the path tail with the target filename
if (typeflag == FTW_F) cout << fpath;
return 0;
}
ftw(dir, fn, depth);myfind() 通过 ftw() 遍历指定目录及其子目录;每个节点把路径、stat 信息与类型交给 callback fn(),由它判断文件名并输出匹配路径。
创建与删除
ofstream out;
out.open(filename, std::ios::out | std::ios::app);
out << str;
out.close();
if (remove(name) == 0) {
cout << "file delete success";
}mycreate() 用 ofstream 写入输入文本;mydelete() 对文件名调用 remove() 并报告结果。
10 / 环境与调试
在 Linux / VMware 环境中完成编译与调试。
报告记录了两项环境问题:VMware 虚拟机启动黑屏,经 BIOS / firmware 中调整 VMware Virtual SCSI Hard Drive 的启动优先级解决;进入 Linux 后发现未安装 g++,随后按提示使用 apt 安装编译器。这些经历属于开发环境排障,而非命令解释器功能本身。
11 / 现在回看
这个项目让我开始理解:pwd、ls、cd、cp 和文件查找并不是黑盒,它们可以拆解为目录流、文件描述符、文件树遍历和系统接口调用。
当时最有效的策略,是把一个看起来复杂的解释器拆成一个个可以独立验证的命令。报告记录了多轮手动调试,未发现阻断已实现命令集的核心问题。今天重新实现时,我会进一步分离命令解析、参数校验、错误处理和系统调用封装,并加入自动化测试与统一错误返回;这些属于今天对 2022 年作品的反思,而非当时已实现的能力。