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

Node.js 模拟 Linux 环境

🧩 项目介绍

该项目使用 Node.js 实现了一个模拟的 Linux 终端环境,支持多种常见的 Linux 命令(如 ls, cd, cat, mkdir, rm 等),所有文件操作都在内存中进行,并持久化到本地文件系统中。适合用于学习 Shell 命令实现原理、文件系统结构或作为教学演示工具。


📦 依赖安装

确保你已安装 Node.js(建议版本 14+),然后运行以下命令安装依赖:

npm install

🚀 启动项目

在项目根目录下运行:

node index.js

你会看到命令提示符:

simu-shell:~$ _

此时你可以输入 Linux 命令进行操作。


📚 支持命令列表

以下是你可以在模拟终端中使用的命令及其基本用法说明:

命令用法示例功能说明
helphelp显示所有可用命令
exitexit退出模拟终端
clearclear清空终端屏幕
historyhistory查看历史命令
pwdpwd显示当前路径
lsls列出当前目录下的文件
llll显示当前目录下的详细文件信息(带类型、大小、修改时间等)
cdcd /home/user切换目录
mkdirmkdir newdir创建目录
rmdirrmdir emptydir删除空目录
rmrm file.txt
rm -r dir
删除文件或目录(递归)
touchtouch newfile.txt创建空文件
echoecho "Hello" > file.txt将字符串写入文件
catcat file.txt查看文件内容
cpcp src.txt dest.txt复制文件或目录
mvmv oldname.txt newname.txt移动或重命名文件/目录
headhead file.txt
head -n 5 file.txt
查看文件前几行
tailtail file.txt
tail -n 5 file.txt
查看文件最后几行
grepgrep "hello" file.txt在文件中查找字符串
findfind file.txt查找文件
statstat file.txt显示文件或目录的详细信息
vimvim file.txt编辑文件
yumyum install https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.26-winx64.zip下载文件
zipzip -r archive.zip test.txt压缩文件
unzipunzip archive.zip -d unzip_target解压文件
rzrz a.txt上传文件
szsz a.txt下载文件

💡 示例操作流程

你可以在模拟终端中依次执行以下命令来测试功能:

help
ls
mkdir test
cd test
touch file.txt
echo "Hello World" > file.txt
cat file.txt
cp file.txt copy.txt
ls
mv copy.txt renamed.txt
cat renamed.txt
rm renamed.txt
ls
cd ..
rm -r test

🧪 测试脚本

项目中提供了 test.md 文件,里面包含了完整的测试命令集,建议你在终端中逐步运行测试命令以验证所有功能是否正常。


🧱 数据持久化机制

项目使用了内存中的虚拟文件系统(VFS),并通过以下方式持久化:

  • 文件内容保存在 storage/files/ 目录下,使用 UUID 命名;
  • 文件系统结构保存在 vfs_data.json 中,每次操作后会自动保存。

📁 项目结构说明

nodejs模拟Linux环境/
├── index.js                  # 主程序入口
├── shell.js                  # 命令处理核心逻辑
├── commands/                 # 各命令的实现
├── vfs.js                    # 虚拟文件系统核心
├── storage.js                # 文件系统结构的持久化
├── fileStorage.js            # 文件内容的持久化
├── utils.js                  # 工具函数(如引号解析)
├── test.md                   # 测试命令列表
├── README.md                 # 本文件
└── package.json              # 项目依赖配置

✅ 项目特点

  • 🧠 使用纯 Node.js 实现,无需依赖外部库(除 uuid);
  • 💾 支持数据持久化,重启后可恢复文件系统状态;
  • 📚 支持大多数常见 Linux 命令;
  • 🛠️ 结构清晰,便于扩展新命令或修改现有逻辑;
  • 🧪 提供完整测试用例,方便验证功能。

📎 扩展建议

你可以根据需要扩展以下功能:

  • 添加新的命令(如 chmod, chmod, grep -r);
  • 支持管道(|)和重定向(>>, <);
  • 支持用户权限管理;
  • 添加命令自动补全;
  • 添加图形化界面(Electron);
  • 支持多用户系统。

源码下载

Node.js 模拟 Linux 环境

核心代码

tool/index.js

// index.js
const readline = require('readline');
const { processCommand } = require('./shell');
const { loadHistory, saveHistory } = require('./historyStorage');const rl = readline.createInterface({input: process.stdin,output: process.stdout,prompt: 'simu-shell:~$ ',
});// 启动时清屏
process.stdout.write('\x1B[2J\x1B[0f');rl.history = loadHistory();
rl.historySize = 100;rl.prompt();rl.on('line', (line) => {const trimmed = line.trim();processCommand(trimmed, rl, () => {rl.prompt();});
}).on('close', () => {saveHistory(rl.history);console.log('\n退出模拟终端');process.exit(0);
});

tool/vfs.js

// vfs.jsconst path = require('path');const fs = require('./storage').load({'/': {type: 'dir',children: {home: {type: 'dir',children: {user: {type: 'dir',children: {'file.txt': { type: 'file', content: 'Hello World' },'notes.md': { type: 'file', content: '# My Notes' }}}}},bin: {type: 'dir',children: {}}}}
});const storage = require('./storage');// 每次修改后自动保存
function persist() {storage.save(fs);
}// 提供一个统一的写入接口
function updateFilesystem(mutateFn) {mutateFn(fs);persist();
}function readdir(path, callback) {const parts = path.split('/').filter(p => p !== '');let current = fs['/'];for (let part of parts) {if (current && current.type === 'dir' && current.children[part]) {current = current.children[part];} else {return callback(`找不到目录: ${path}`);}}callback(null, Object.keys(current.children));
}function chdir(path, currentDir, callback) {const resolvedPath = resolvePath(path, currentDir);const parts = resolvedPath.split('/').filter(p => p !== '');let current = fs['/'];for (let part of parts) {if (current && current.type === 'dir' && current.children[part]) {current = current.children[part];} else {return callback(`找不到目录: ${resolvedPath}`);}}callback(null, resolvedPath);
}function resolvePath(path, currentDir) {if (path.startsWith('/')) return path;if (currentDir === "/") return normalizePath(`/${path}`);return normalizePath(`${currentDir}/${path}`);
}function normalizePath(inputPath) {// 使用 path.normalize 解析 .. 等相对路径let normalized = path.normalize(inputPath).replace(/^(\.\.\/|\/)?/, '')  // 移除开头的 ./ ../ /.replace(/\\/g, '/');          // 统一为正斜杠if (normalized.startsWith("/")) {return normalized;}return '/' + normalized;
}function getNodeByPath(path) {const parts = path.split('/').filter(p => p !== '');let current = fs['/'];for (let part of parts) {if (current && current.type === 'dir' && current.children[part]) {current = current.children[part];} else {return null;}}return current;
}function getDirStats(node) {let totalSize = 0;let latestTime = new Date(node.mtime);function traverse(current) {if (current.type === 'file') {totalSize += current.size;const mtime = new Date(current.mtime);if (mtime > latestTime) latestTime = mtime;} else if (current.type === 'dir') {for (let child of Object.values(current.children)) {traverse(child);}}}traverse(node);return {size: totalSize,mtime: latestTime.toISOString()};
}module.exports = {fs,readdir,chdir,resolvePath,normalizePath,updateFilesystem,getNodeByPath,getDirStats
};

tool/shell.js

// shell.js
const vfs = require('./vfs');
const fs = vfs.fs;const commands = {cat: require('./commands/cat'),cd: require('./commands/cd'),clear: require('./commands/clear'),cp: require('./commands/cp'),echo: require('./commands/echo'),exit: require('./commands/exit'),find: require('./commands/find'),grep: require('./commands/grep'),head: require('./commands/head'),help: require('./commands/help'),history: require('./commands/history'),ll: require('./commands/ll'),ls: require('./commands/ls'),mkdir: require('./commands/mkdir'),mv: require('./commands/mv'),pwd: require('./commands/pwd'),rm: require('./commands/rm'),rmdir: require('./commands/rmdir'),stat: require('./commands/stat'),tail: require('./commands/tail'),touch: require('./commands/touch'),vim: require('./commands/vim'),yum: require('./commands/yum'),zip: require('./commands/zip'),unzip: require('./commands/unzip'),rz: require('./commands/rz'),sz: require('./commands/sz'),
};let currentDir = '/home/user';function processCommand(input, rl, promptCall) {const args = input.trim().split(/\s+/);const cmd = args[0];if (!commands[cmd]) {console.log(`命令未找到: ${cmd}`);promptCall();return;} else if (cmd === 'history') {commands[cmd].execute([], currentDir, rl);promptCall();return;} else if (cmd === 'vim') {commands[cmd].execute(args, currentDir, rl);return;} else if (cmd === 'yum') {commands[cmd].execute(args, currentDir, rl);return;} else if (cmd === 'exit') {commands[cmd].execute(rl);return;}commands[cmd].execute(args, currentDir, (newDir) => {if (newDir) currentDir = newDir;});promptCall();
}module.exports = { processCommand };

演示截图

在这里插入图片描述

http://www.xdnf.cn/news/16262.html

相关文章:

  • 【每天一个知识点】GAN(生成对抗网络,Generative Adversarial Network)
  • Whisper语音转文字
  • 【洛谷】单向链表、队列安排、约瑟夫问题(list相关算法题)
  • 互联网应用主流框架整合 Spring Boot开发
  • Linux DNS 服务器正反向解析
  • 【IMMCKF】基于容积卡尔曼滤波(CKF)的多模型交互的定位程序,模型为CV和CT,三维环境,matlab代码|附下载链接
  • Nestjs框架: 基于Mongodb的多租户功能集成和优化
  • 算子推理是什么
  • 电脑开机后网络连接慢?
  • (Python)文件储存的认识,文件路径(文件储存基础教程)(Windows系统文件路径)(基础教程)
  • 【17】C# 窗体应用WinForm ——【文本框TextBox、富文本框RichTextBox 】属性、方法、实例应用
  • C++:list(2)list的模拟实现
  • Java中配置两个r2db连接不同的数据库
  • JavaScript:现代Web开发的核心动力
  • Mistral AI开源 Magistral-Small-2507
  • C++查询mysql数据
  • Codeforces Round 181 (Rated for Div. 2)
  • Bert项目--新闻标题文本分类
  • DAY31 整数矩阵及其运算
  • 告别镜像拉取慢!CNB无痛加速方案,一键起飞
  • [论文阅读] 人工智能 + 软件工程 | NoCode-bench:评估LLM无代码功能添加能力的新基准
  • JVM常见工具
  • swagger基本注解@Tag、@Operation、@Parameters、@Parameter、@ApiResponse、@Schema
  • 基于图神经网络的星间路由与计算卸载强化学习算法设计与实现
  • 【Linux手册】操作系统如何管理存储在外设上的文件
  • 基于 Claude Code 与 BrowserCat MCP 的浏览器自动化全链路构建实践
  • iOS 26,双版本更新来了
  • 【web大前端】001_前端开发入门:创建你的第一个网页
  • 二十八、【Linux系统域名解析】DNS安装、子域授权、缓存DNS、分离解析、多域名解析
  • 前端开发 Vue 结合Sentry 实现性能监控