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.pswp.cn/web/90665.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90665.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90665.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HAProxy 實驗指南:從零開始搭建高可用負載均衡系統

引言HAProxy&#xff08;High Availability Proxy&#xff09;是一款高性能的TCP/HTTP負載均衡器和代理服務器&#xff0c;廣泛用于構建高可用、可擴展的Web架構。它由法國開發者Willy Tarreau于2000年開發&#xff0c;如今已成為開源社區和企業級應用中不可或缺的工具。HAProx…

2.10DOM和BOM插入/移除/克隆

1.DOM創建/插入/移除/克隆1.1創建元素前面我們使用過 document.write 方法寫入一個元素&#xff1a;這種方式寫起來非常便捷&#xff0c;但是對于復雜的內容、元素關系拼接并不方便&#xff1b;它是在早期沒有 DOM 的時候使用的方案&#xff0c;目前依然被保留了下來&#xff1…

華為倉頡編程語言的表達式及其特點

華為倉頡編程語言的表達式及其特點 倉頡&#xff08;Cangjie&#xff09;語言的表達式有一個明顯的特點&#xff0c;范圍不再局限于傳統算術運算&#xff0c;而是擴展到條件表達式、循環表達式等多種類型&#xff0c;每種表達式均有確定的類型和值。 傳統基本表達式&#xff0…

【linux】keepalived

一.高可用集群1.1 集群類型LB&#xff1a;Load Balance 負載均衡 LVS/HAProxy/nginx&#xff08;http/upstream, stream/upstream&#xff09; HA&#xff1a;High Availability 高可用集群 數據庫、Redis SPoF: Single Point of Failure&#xff0c;解決單點故障 HPC&#xff…

Webpack配置原理

一、Loader&#xff1a; 1、定義&#xff1a;將不同類型的文件轉換為 webpack 可識別的模塊2、分類&#xff1a; ① pre&#xff1a; 前置 loader &#xff08;1&#xff09;配置&#xff1a;在 webpack 配置文件中通過enforce進行指定 loader的優先級配置&#xff08;2&#x…

對比JS“上下文”與“作用域”

下面從定義、特性、示例&#xff0c;以及在代碼分析中何時側重“上下文”&#xff08;Execution Context/this&#xff09;和何時側重“作用域”&#xff08;Scope/變量查找&#xff09;&#xff0c;以及二者結合的場景來做對比和指導。一、概念對比 | 維度 | 上下文&#xff0…

如何做數據增強?

目錄 1、為什么要做數據增強&#xff1f; 2、圖像數據增強&#xff1f; 3、文本與音頻數據增強&#xff1f; 4、高級數據增強&#xff1f; 數據增強技術就像是一種“造數據”的魔法&#xff0c;通過對原始數據進行各種變換&#xff0c;生成新的樣本&#xff0c;從而提高模型…

Go by Example

網頁地址Go by Example 中文版 Github倉庫地址mmcgrana/gobyexample&#xff1a;按示例進行 HelloWorld package mainimport ("fmt" )func main() {fmt.Println("Hello World") } Hello World 值 package mainimport ("fmt" )func main() {…

ClickHouse高性能實時分析數據庫-消費實時數據流(消費kafka)

告別等待&#xff0c;秒級響應&#xff01;這不只是教程&#xff0c;這是你駕馭PB級數據的超能力&#xff01;我的ClickHouse視頻課&#xff0c;凝練十年實戰精華&#xff0c;從入門到精通&#xff0c;從單機到集群。點開它&#xff0c;讓數據處理速度快到飛起&#xff0c;讓你…

電子電氣架構 --- 車載軟件與樣件產品交付的方法

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 簡單,單純,喜歡獨處,獨來獨往,不易合同頻過著接地氣的生活,除了生存溫飽問題之外,沒有什么過多的欲望,表面看起來很高冷,內心熱情,如果你身…

C++:STL中vector的使用和模擬實現

在上一篇中講到了string類&#xff0c;string并不屬于STL中因為string出現的比STL早&#xff0c;但是在使用方法上兩者有相似之處&#xff0c;學習完string后再來看vector會容易的多&#xff0c;接著往下閱讀&#xff0c;一定會有收獲滴&#xff01; 目錄 vector的介紹 vect…

倉庫管理的流程、績效和解決方案?

什么是倉庫管理&#xff1f; 倉庫管理涉及對所有倉庫運營的日常監督。一個全面、集成的倉庫管理解決方案采用行業最佳實踐&#xff0c;并涵蓋使高效運營得以實現的所有基本要素。這些要素包括分銷和庫存管理、倉庫勞動力管理以及業務支持服務。此外&#xff0c;由內部提供或與服…

TIM 實現定時中斷【STM32L4】【實操】

使用定時器實現定時中斷的功能&#xff1a;比如每1ms進入中斷處理函數使用STM32CubeMX配置TIM初始化先了解每個參數的含義&#xff0c;在進行配置Counter Settings: 計數器基本設置Prescaler(PSC): 預分頻器&#xff0c;設置預分頻器系數Counter Mode: 技術模式&#xff0c;…

Elasticsearch 的聚合(Aggregations)操作詳解

目錄 1. 概述 2. 聚合類型分類詳解 2.1 桶聚合&#xff08;Bucket Aggregations&#xff09; 2.1.1 基礎桶聚合 2.1.2 特殊桶聚合 2.1.3 高級桶聚合 2.2 指標聚合&#xff08;Metric Aggregations&#xff09; 2.2.1 單值指標聚合&#xff08;Single-value Metrics&am…

電子電氣架構 --- 高階智能駕駛對E/E架構的新要求

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 做到欲望極簡,了解自己的真實欲望,不受外在潮流的影響,不盲從,不跟風。把自己的精力全部用在自己。一是去掉多余,凡事找規律,基礎是誠信;二是…

0.深度學習環境配置步驟

0.深度學習環境配置步驟 這里介紹深度學習環境配置詳細步驟&#xff0c;包括安裝軟件&#xff0c;每一步都有安裝時的截圖&#xff08;后續持續更新&#xff0c;敬請關注&#xff09; 目錄如下&#xff1a; 1.安裝anaconda 2.安裝CUDA 3.安裝CU_DNN 4.安裝pytorch

在 Azure 中配置 SMS 與 OTP

1. Azure Active Directory B2C (AAD B2C) 中的 SMS/OTP 身份驗證 1.1. 現狀與原理&#xff1a;電話注冊與登錄 Azure Active Directory B2C (AAD B2C) 提供了將電話號碼作為用戶身份標識進行注冊和登錄的功能&#xff0c;旨在為用戶提供一種便捷的替代傳統電子郵件或用戶名登錄…

簡單實現支付密碼的頁面及輸入效果

干我們這行&#xff0c;風吹日曬不到&#xff0c;就怕甲方突發奇想。 今天客戶要做一個安全密碼前置校驗&#xff0c;還要做成支付寶那種效果。ps:android端 心理吐槽了一萬遍以后&#xff0c;還是得面對現實。 先用通義問一遍&#xff0c;給了兩個方案&#xff0c;要么自己寫&…

proxmox 解決docker容器MongoDB創建報錯MongoDB 5.0+ requires a CPU with AVX support

目錄 最簡單直接的方式 測試MongoDB docker compose的安裝shell腳本 驗證訪問 最簡單直接的方式 讓虛擬機直接使用宿主機的物理 CPU 功能標志。 打開 Proxmox Web UI。 選擇你的 VM → 硬件 (Hardware) → CPU → 點擊 編輯 (Edit)。 將 CPU 類型改為 host。 確認并重啟…

向前滾動累加SQL 實現思路

一、業務背景在經營分析場景里&#xff0c;我們經常需要回答&#xff1a;“截至今天&#xff0c;過去 N 天/月/周累計發生了多少&#xff1f;”“把維度切到省、市、房型、項目經理、代理商等&#xff0c;結果又是什么&#xff1f;”本文用兩個真實需求做演示&#xff1a;以天為…