feat: expand linux curriculum to ops-focused full-scenario blueprint

This commit is contained in:
likingcode
2026-03-10 08:05:58 +08:00
parent 5ca924cadd
commit de7631985d
3 changed files with 291 additions and 320 deletions

359
COURSE.md
View File

@@ -1,274 +1,281 @@
# Linux 学习平台课程设计(重构版)
# Linux 学习平台课程设计(运维全场景重构版)
## 总目标
这套课程不再只是 Linux 命令入门,也不是答题闯关页,而是:
> **面向运维强相关场景的 Linux 系统学习平台**
目标是帮助学习者逐步形成三层能力:
1. **命令理解能力**:知道命令在解决什么问题
2. **系统认知能力**:知道 Linux 系统是怎么组织和运行的
3. **运维场景能力**:知道遇到问题时该用哪组命令排查和处理
---
## 设计原则
这次课程重构,目标不再是“闯关刷题”,而是建立一套**适合系统学习 Linux 的知识结构**。
核心原则:
- **先理解,再操作**
- **先场景,再命令**
- **先最小可用,再扩展参数**
- **练习服务于理解,不反客为主**
- **每个模块都能迁移到真实工作场景**
- **从经典 Linux / Unix 教材与运维认证体系中吸收结构感**
- **尽量覆盖运维强相关全场景**
---
## 课程结构
## 课程组织方式
课程分为 6 大模块,不再按简单等级推进,而按学习逻辑推进。
课程采用三层结构:
### 第一层:知识模块
按 Linux/运维核心领域拆分模块。
### 第二层:课时
每个课时围绕一个核心问题或一组密切相关命令展开。
### 第三层:练习
练习分为:
- 理解题
- 操作题
- 场景题
练习是为了巩固,不再主导整个平台体验。
---
## 完整课程蓝图10 大模块)
### 模块 1建立 Linux 基本认知
目标:搞清楚“我在哪、我看到什么、我怎么移动”
目标:搞清楚终端、路径、目录、文件的基本世界观
包含内容
- 什么是终端 / Shell
- 什么是当前目录
- 什么是绝对路径 / 相对路径
- `pwd`
- `ls`
- `cd`
- `echo`
- `cat`
包含:
- 终端与 Shell
- 绝对路径 / 相对路径
- pwd / ls / cd / cat / echo
输出能力:
-在目录中定位自己
-懂基路径
-查看基础文件内容
- 能定位自己
-懂基路径
-基础文件内容
---
### 模块 2文件与目录操作
目标:建立文件系统操作能力。
包含内容
- 文件目录的区别
- 创建 / 复制 / 移动 / 删除
- `mkdir`
- `touch`
- `cp`
- `mv`
- `rm`
- `stat`
包含:
- 文件目录的区别
- mkdir / touch / cp / mv / rm / stat
- 文件生命周期:创建、备份、迁移、清理
输出能力:
- 能完成日常文件
- 能理解“创建、备份、迁移、清理”四种动作
- 能完成基础文件
- 能理解文件操作的风险和意义
---
### 模块 3阅读与筛选信息
目标:学会从文件和日志中找信息
目标:建立日志、配置、文本信息处理能力
包含内容
- `head`
- `tail`
- `grep`
- `wc`
- `sort`
- `find`
- 日志查看思路
- 搜索与过滤思路
包含:
- head / tail / grep / wc / sort / find
- 搜索与筛选思路
- 日志阅读思路
输出能力:
- 能读日志
-关键词
- 能定位配置文件
-关键词
- 能定位文件
- 能做基础统计
---
### 模块 4系统状态与资源认知
目标:知道系统现在在干什么。
目标:知道一台 Linux 机器此刻在运行什么。
包含内容
- 进程是什么
- 磁盘 / 内存 / 挂载点是什么
- `ps`
- `top`
- `df`
- `du`
- `free`
- `mount`
- `history`
包含:
- 进程、负载、CPU、内存、磁盘、挂载点
- ps / top / uptime / free / df / du / mount / lsof
输出能力:
- 能做基础排查
-看懂资源占用
- 能理解系统运行状态
- 能做基础资源排查
-理解系统是否正常运行
---
### 模块 5网络与服务基础
目标:建立 Linux 运维里的连接意识
### 模块 5服务与日志排障
目标:围绕服务故障建立排查链路
包含内容
- 网络接口是什么
- 端口与监听是什么
- `ifconfig` / `ip addr`
- `ping`
- `ss` / `netstat`
- `curl`
- `wget`
- `which` / `whereis`
包含:
- systemd 基础
- 服务状态 / 启停 / 自启动
- journalctl
- 进程、端口、日志之间的关系
- systemctl / service / journalctl / kill / pkill / nohup
输出能力:
- 能处理“服务没起来 / 起了但不可用 / 日志报错”类问题
---
### 模块 6网络与连接排查
目标:建立网络、监听、请求和服务可达性的认知。
包含:
- 网卡 / IP / 端口 / 监听 / 连通性
- ifconfig / ip addr / ping / ss / netstat / curl / wget / traceroute / dig
输出能力:
- 能判断服务通不通
-理解“域名、端口、监听、请求”的基本关系
-区分网络层、端口层、HTTP 层的问题
---
### 模块 6:权限、习惯与实际运维思维
目标:从“会敲命令”过渡到“知道为什么这么做”。
### 模块 7:权限、用户与安全基础
目标:从“能执行”提升到“知道该不该执行”。
包含内容
- 权限模型基础
- `chmod`
- `chown`
- `chgrp`
- `alias`
- `export`
- `tar`
- `crontab`
- 常见运维习惯
- 风险命令认知
包含:
- 用户、组、权限模型
- chmod / chown / chgrp / whoami / id / passwd / sudo / su
- 最小权限原则
- 高风险命令意识
输出能力:
-理解权限修改的意义
-建立基础运维安全感
- 能开始形成 Linux 使用习惯
-处理基础权限问题
-理解安全边界
---
## 每个课时的新结构
### 模块 8软件包、环境与命令定位
目标:理解软件从哪里来、命令为什么能执行、版本怎么查。
每一课统一用下面 6 段结构
包含
- PATH 与命令查找
- which / whereis / env / export / alias
- apt / dpkg / yum / rpm
### 1. 学什么
一句话说清这个命令/主题在解决什么问题。
输出能力:
- 能定位命令来源
- 能查版本、查安装包、查环境变量问题
### 2. 为什么重要
它在真实 Linux 使用、开发、运维里有什么价值。
---
### 3. 核心知识点
包括:
- 命令作用
- 常见参数
- 常见组合
- 输出怎么看
- 容易误解的点
### 模块 9自动化、归档与运维习惯
目标:建立“批量处理、定时执行、可重复操作”的意识。
### 4. 最小示例
给 2~4 个最有代表性的示例。
包含:
- 重定向 / 管道
- crontab
- tar / gzip / zip / unzip
- history
- Shell 习惯
### 5. 常见场景
把命令放进真实场景里:
- 查配置
- 查日志
- 找文件
- 看资源
- 改权限
输出能力:
- 能做基础自动化
- 能做备份和简单定时任务
- 能形成更稳妥的命令行习惯
### 6. 练习题
练习题不再喧宾夺主,而是用于确认理解。
---
### 模块 10运维综合实战场景
目标:把前面所有能力真正串起来。
典型场景:
- 服务无法访问排查
- 磁盘爆满排查
- 登录失败排查
- Nginx / 应用日志排查
- 发布后服务未启动
- 备份与恢复演练
输出能力:
- 知道不是背命令,而是围绕问题组织命令链路
---
## 每课统一结构
每个课时都按下列结构组织:
1. **学什么**
2. **为什么重要**
3. **核心知识点**
4. **最小示例**
5. **常见误区**
6. **典型场景**
7. **练习题**
8. **课后总结 / 迁移建议**(后续补齐)
---
## 练习设计原则
练习题分成 3 类:
### A. 理解题
有没有理解命令用途。
例:
- 查看当前目录应该用什么命令?
- 为什么 `ls -a` 会比 `ls` 多看到东西?
有没有理解命令用途和思路
### B. 操作题
验能否正确写出命令。
例:
- 进入 `/tmp`
- 查找 `/etc` 下所有 `.conf` 文件
查是否能写出正确命令。
### C. 场景题
是否能把命令放进真实问题中。
例:
- 日志太大,不想全看,只看最后 20 行怎么办?
- 想找出包含 `error` 的日志应该怎么做?
是否能把命令放进真实运维问题中。
> 练习不是为了“刷过去”,而是为了确认:你是不是真的知道这个命令为什么存在。
---
## 页面呈现结构(学习优先)
## 页面结构原则
前端页面不再以“终端交互”为主,而改为:
### 左侧:课程目录
### 左侧:课程地图
- 模块
- 小节
- 学习进度
- 课时
- 学习路径
### 中间:学习正文
- 概念讲解
- 示例
- 场景
- 总结
### 中间:正文学习区
- 讲解优先
- 示例优先
- 场景优先
### 右侧:知识辅助
- 关键概念
### 右侧:辅助理解区
- 易错点
- 相关命令
- 推荐练习
- 场景提示
- 理解型问题
### 底部练习区
- 简洁练习,不抢正文
- 只做必要反馈
- 重点是“学完再练”
### 底部 / 内嵌:轻练习区
- 练习服务于学习
- 保持必要但不过分喧宾夺主
---
## 新平台定位
## 吸收的“教材气质”
重构后的 Linux 平台定位为
这套平台后续会持续内化这些来源的设计方法
- 经典 Linux / Unix 入门教材的结构感
- man / 官方文档的准确性
- RHCSA / RHCE / LPIC 一类认证体系的能力递进
- 真实运维工作流里的问题链路
> **Linux 系统学习平台 + 轻量练习环境**
不是搬教材,而是:
不是刷题站,也不是单纯命令模拟器。
目标用户看到平台后,应该感受到:
- 这是能认真学东西的
- 不是只会点按钮
- 不是只会猜答案
- 学完真的能迁移到实际 Linux 使用场景
> **把经典教材与运维经验内化后,重新设计成适合平台学习的课程。**
---
## 重构顺序
## 当前重构阶段
### 第一阶段:课程蓝图重构
- 重写课程结构
- 重写模块划分
- 重写题目组织方式
### 已完成
- 平台方向从交互优先改成学习优先
- 前 3 个模块已落到课程结构中
- 页面结构已切为知识正文型
### 第二阶段:前 3 个模块内容重写
- Linux 基本认知
- 文件与目录操作
- 阅读与筛选信息
### 第三阶段:页面重构
- 课程目录页
- 学习正文页
- 轻练习区
### 第四阶段:后续模块补齐
- 系统状态
- 网络基础
- 权限与运维习惯
### 下一步
- 扩完整个 10 模块蓝图到课程数据
- 逐步补模块 4~10 的详细课时
- 增加“场景专题”页,把命令真正串成运维链路
---
## 当前结论
## 一句话定位
这次不是“继续补旧平台”,而是:
> **把 Linux 平台从“交互导向”改造成“知识导向”的系统学习平台。**
后续所有改动,以这个文档为准。
> **这是一个吸收经典 Linux 教材与运维训练体系后,面向运维强相关全场景重构的 Linux 学习平台。**

View File

@@ -1,13 +1,13 @@
{
"meta": {
"version": "4.0",
"title": "Linux 系统学习课程(重构版)",
"version": "4.1",
"title": "Linux 系统学习课程(运维全场景版)",
"author": "OpenClaw Dev",
"updated": "2026-03-10",
"description": "强调知识理解、场景迁移与轻量练习的 Linux 学习课程",
"module_count": 6,
"total_lessons": 18,
"total_exercises": 54
"description": "强调知识理解、场景迁移与运维全场景覆盖的 Linux 学习课程",
"module_count": 10,
"total_lessons": 30,
"total_exercises": 90
},
"modules": [
{
@@ -20,46 +20,15 @@
"title": "认识当前目录pwd",
"goal": "理解当前工作目录的意义,知道自己在文件系统中的位置。",
"why_it_matters": "很多 Linux 操作依赖路径。如果不知道自己当前在哪,后续命令容易出错。",
"concepts": [
"当前工作目录",
"绝对路径与相对路径",
"为什么要先定位再操作"
],
"concepts": ["当前工作目录", "绝对路径与相对路径", "为什么要先定位再操作"],
"command": "pwd",
"examples": [
"pwd",
"cd /tmp && pwd"
],
"pitfalls": [
"以为终端默认总在同一个目录",
"不分清当前目录和目标目录"
],
"scenarios": [
"切目录后确认自己到了哪里",
"写脚本前确认当前运行位置"
],
"examples": ["pwd", "cd /tmp && pwd"],
"pitfalls": ["以为终端默认总在同一个目录", "不分清当前目录和目标目录"],
"scenarios": ["切目录后确认自己到了哪里", "写脚本前确认当前运行位置"],
"exercises": [
{
"id": "m1_l1_e1",
"type": "understanding",
"question": "查看当前工作目录应该使用什么命令?",
"answer": "pwd"
},
{
"id": "m1_l1_e2",
"type": "operation",
"title": "输出当前目录",
"hint": "直接输入 pwd",
"success_test": "cmd == 'pwd'",
"solution": ["pwd"],
"success_msg": "你已经能确认自己所在的位置了。"
},
{
"id": "m1_l1_e3",
"type": "scenario",
"question": "如果你不确定自己当前在哪个目录,第一反应应该做什么?",
"answer": "先执行 pwd 确认当前目录"
}
{"id": "m1_l1_e1", "type": "understanding", "question": "查看当前工作目录应该使用什么命令?", "answer": "pwd"},
{"id": "m1_l1_e2", "type": "operation", "title": "输出当前目录", "hint": "直接输入 pwd", "success_test": "cmd == 'pwd'", "solution": ["pwd"], "success_msg": "你已经能确认自己所在的位置了。"},
{"id": "m1_l1_e3", "type": "scenario", "question": "如果你不确定自己当前在哪个目录,第一反应应该做什么?", "answer": "先执行 pwd 确认当前目录"}
]
},
{
@@ -67,50 +36,15 @@
"title": "看见目录内容ls",
"goal": "理解 ls 的作用,并掌握查看隐藏文件和详细信息的基本方式。",
"why_it_matters": "Linux 下很多探索行为都从 ls 开始,它决定你如何观察目录结构。",
"concepts": [
"目录内容查看",
"隐藏文件",
"长列表信息"
],
"concepts": ["目录内容查看", "隐藏文件", "长列表信息"],
"command": "ls",
"examples": [
"ls",
"ls -la",
"ls -lh /etc"
],
"pitfalls": [
"误以为 ls 看不到的文件就不存在",
"不会区分普通 ls 和 ls -l 的用途"
],
"scenarios": [
"排查目录里到底有哪些文件",
"检查配置目录中是否有隐藏文件"
],
"examples": ["ls", "ls -la", "ls -lh /etc"],
"pitfalls": ["误以为 ls 看不到的文件就不存在", "不会区分普通 ls 和 ls -l 的用途"],
"scenarios": ["排查目录里到底有哪些文件", "检查配置目录中是否有隐藏文件"],
"exercises": [
{
"id": "m1_l2_e1",
"type": "understanding",
"question": "为什么 ls -a 会比 ls 多看到一些文件?",
"answer": "因为它会显示隐藏文件,包括以点开头的文件"
},
{
"id": "m1_l2_e2",
"type": "operation",
"title": "列出当前目录内容",
"hint": "输入 ls",
"success_test": "cmd == 'ls'",
"solution": ["ls"],
"success_msg": "你已经会观察目录内容了。"
},
{
"id": "m1_l2_e3",
"type": "operation",
"title": "显示隐藏文件和详细信息",
"hint": "使用 ls -la",
"success_test": "cmd == 'ls -la' or cmd == 'ls -al'",
"solution": ["ls -la", "ls -al"],
"success_msg": "你已经会用更完整的方式查看目录了。"
}
{"id": "m1_l2_e1", "type": "understanding", "question": "为什么 ls -a 会比 ls 多看到一些文件?", "answer": "因为它会显示隐藏文件,包括以点开头的文件"},
{"id": "m1_l2_e2", "type": "operation", "title": "列出当前目录内容", "hint": "输入 ls", "success_test": "cmd == 'ls'", "solution": ["ls"], "success_msg": "你已经会观察目录内容了。"},
{"id": "m1_l2_e3", "type": "operation", "title": "显示隐藏文件和详细信息", "hint": "使用 ls -la", "success_test": "cmd == 'ls -la' or cmd == 'ls -al'", "solution": ["ls -la", "ls -al"], "success_msg": "你已经会用更完整的方式查看目录了。"}
]
},
{
@@ -118,55 +52,15 @@
"title": "移动、读文件、输出文本",
"goal": "掌握 cd、cat、echo 这些最基础但最常用的命令。",
"why_it_matters": "这三个命令几乎贯穿 Linux 入门阶段的所有练习。",
"concepts": [
"切换目录",
"读取文件",
"输出文本与变量"
],
"concepts": ["切换目录", "读取文件", "输出文本与变量"],
"command": "cd / cat / echo",
"examples": [
"cd /tmp",
"cat /etc/hosts",
"echo Hello Linux"
],
"pitfalls": [
"把 cd 和 ls 混用",
"用 cat 去看过大的文件",
"不知道 echo 也常用于脚本调试"
],
"scenarios": [
"进入指定目录继续操作",
"快速读取配置文件",
"验证变量和命令输出"
],
"examples": ["cd /tmp", "cat /etc/hosts", "echo Hello Linux"],
"pitfalls": ["把 cd 和 ls 混用", "用 cat 去看过大的文件", "不知道 echo 也常用于脚本调试"],
"scenarios": ["进入指定目录继续操作", "快速读取配置文件", "验证变量和命令输出"],
"exercises": [
{
"id": "m1_l3_e1",
"type": "operation",
"title": "进入 /tmp 目录",
"hint": "cd /tmp",
"success_test": "cmd == 'cd /tmp' and cwd == '/tmp'",
"solution": ["cd /tmp"],
"success_msg": "你已经能切换到目标目录了。"
},
{
"id": "m1_l3_e2",
"type": "operation",
"title": "读取 hosts 文件",
"hint": "cat /etc/hosts",
"success_test": "cmd == 'cat /etc/hosts' and 'localhost' in output",
"solution": ["cat /etc/hosts"],
"success_msg": "你已经会读取基础文本文件了。"
},
{
"id": "m1_l3_e3",
"type": "operation",
"title": "输出 Hello Linux",
"hint": "echo Hello Linux",
"success_test": "cmd == 'echo Hello Linux' and 'Hello Linux' in output",
"solution": ["echo Hello Linux"],
"success_msg": "你已经掌握了最基础的文本输出命令。"
}
{"id": "m1_l3_e1", "type": "operation", "title": "进入 /tmp 目录", "hint": "cd /tmp", "success_test": "cmd == 'cd /tmp' and cwd == '/tmp'", "solution": ["cd /tmp"], "success_msg": "你已经能切换到目标目录了。"},
{"id": "m1_l3_e2", "type": "operation", "title": "读取 hosts 文件", "hint": "cat /etc/hosts", "success_test": "cmd == 'cat /etc/hosts' and 'localhost' in output", "solution": ["cat /etc/hosts"], "success_msg": "你已经会读取基础文本文件了。"},
{"id": "m1_l3_e3", "type": "operation", "title": "输出 Hello Linux", "hint": "echo Hello Linux", "success_test": "cmd == 'echo Hello Linux' and 'Hello Linux' in output", "solution": ["echo Hello Linux"], "success_msg": "你已经掌握了最基础的文本输出命令。"}
]
}
]
@@ -242,8 +136,8 @@
"pitfalls": ["大文件直接 cat 影响阅读效率", "不会区分查看历史和跟踪新增日志"],
"scenarios": ["看配置文件开头", "盯日志尾部排查实时错误"],
"exercises": [
{"id": "m3_l1_e1", "type": "operation", "title": "查看 syslog 前 5 行", "hint": "head -n 5 /var/log/syslog", "success_test": "(cmd == 'head -n 5 /var/log/syslog' or cmd == 'head -5 /var/log/syslog') and len(output.split('\n')) >= 5", "solution": ["head -n 5 /var/log/syslog", "head -5 /var/log/syslog"], "success_msg": "你已经会局部查看大文件开头了。"},
{"id": "m3_l1_e2", "type": "operation", "title": "查看 syslog 最后 3 行", "hint": "tail -n 3 /var/log/syslog", "success_test": "(cmd == 'tail -n 3 /var/log/syslog' or cmd == 'tail -3 /var/log/syslog') and len(output.split('\n')) >= 3", "solution": ["tail -n 3 /var/log/syslog", "tail -3 /var/log/syslog"], "success_msg": "你已经会快速查看日志尾部了。"},
{"id": "m3_l1_e1", "type": "operation", "title": "查看 syslog 前 5 行", "hint": "head -n 5 /var/log/syslog", "success_test": "(cmd == 'head -n 5 /var/log/syslog' or cmd == 'head -5 /var/log/syslog') and len(output.split('\\n')) >= 5", "solution": ["head -n 5 /var/log/syslog", "head -5 /var/log/syslog"], "success_msg": "你已经会局部查看大文件开头了。"},
{"id": "m3_l1_e2", "type": "operation", "title": "查看 syslog 最后 3 行", "hint": "tail -n 3 /var/log/syslog", "success_test": "(cmd == 'tail -n 3 /var/log/syslog' or cmd == 'tail -3 /var/log/syslog') and len(output.split('\\n')) >= 3", "solution": ["tail -n 3 /var/log/syslog", "tail -3 /var/log/syslog"], "success_msg": "你已经会快速查看日志尾部了。"},
{"id": "m3_l1_e3", "type": "scenario", "question": "为什么排查线上报错时更常先用 tail 而不是 cat", "answer": "因为日志通常很大tail 可以更快聚焦最近发生的问题"}
]
},
@@ -280,6 +174,76 @@
]
}
]
},
{
"id": "module_4_system_state",
"title": "模块 4系统状态与资源认知",
"summary": "学习如何看进程、负载、磁盘、内存和挂载信息,建立系统状态判断能力。",
"lessons": [
{"id":"m4_l1_process","title":"看进程ps / top","goal":"理解 Linux 中的进程概念,知道如何查看系统正在运行什么。","why_it_matters":"绝大多数服务故障、卡顿和异常都要先看进程。","concepts":["进程与服务","前台与后台","ps 和 top 的区别"],"command":"ps / top","examples":["ps aux","ps -ef","top"],"pitfalls":["只会看进程名,不会看状态","把存在进程等同于服务可用"],"scenarios":["确认服务进程是否存在","定位高 CPU 进程"],"exercises":[{"id":"m4_l1_e1","type":"operation","title":"查看所有进程","hint":"ps aux","success_test":"cmd == 'ps aux' and 'PID' in output","solution":["ps aux"],"success_msg":"你已经会查看系统进程了。"},{"id":"m4_l1_e2","type":"understanding","question":"为什么看到进程存在,不代表服务一定可用?","answer":"因为进程存在只说明程序在运行,不代表端口监听、配置、依赖或接口一定正常"},{"id":"m4_l1_e3","type":"scenario","question":"排查“服务似乎没启动”时,第一步通常可以用什么命令?","answer":"先用 ps aux 或 ps -ef 查看相关进程是否存在"}]},
{"id":"m4_l2_disk_memory","title":"看磁盘与内存df / du / free","goal":"掌握查看磁盘使用、目录占用和内存情况的基础方法。","why_it_matters":"磁盘爆满、内存紧张是最常见的线上问题之一。","concepts":["磁盘空间 vs 目录占用","物理内存与可用内存","df 和 du 的区别"],"command":"df / du / free","examples":["df -h","du -sh /var/log","free -h"],"pitfalls":["只会看总磁盘,不会看哪个目录占用大","误把 free 的 used 当成唯一关键指标"],"scenarios":["排查磁盘已满","定位大目录","查看内存是否紧张"],"exercises":[{"id":"m4_l2_e1","type":"operation","title":"查看磁盘空间","hint":"df -h","success_test":"cmd == 'df -h' and 'Filesystem' in output","solution":["df -h"],"success_msg":"你已经会看磁盘使用情况了。"},{"id":"m4_l2_e2","type":"operation","title":"查看 /sandbox 目录大小","hint":"du -sh /sandbox","success_test":"cmd == 'du -sh /sandbox' and '/sandbox' in output","solution":["du -sh /sandbox"],"success_msg":"你已经会看目录占用了。"},{"id":"m4_l2_e3","type":"understanding","question":"df 和 du 的核心区别是什么?","answer":"df 看文件系统层面的磁盘使用du 看目录或文件占用大小"}]},
{"id":"m4_l3_mount_history","title":"运行时间、挂载点与历史命令","goal":"建立系统运行时间、挂载结构与命令习惯认知。","why_it_matters":"理解机器运行了多久、磁盘挂载在哪里、最近执行过什么命令,是运维日常的基础信息。","concepts":["uptime 的含义","挂载点","history 复盘"],"command":"uptime / mount / history","examples":["uptime","mount","history -n 5"],"pitfalls":["不看历史重复犯错","忽略挂载点导致排查路径错位"],"scenarios":["查看机器是否重启过","判断目录属于哪个挂载点","复盘最近操作"],"exercises":[{"id":"m4_l3_e1","type":"operation","title":"查看系统运行时间","hint":"uptime","success_test":"cmd == 'uptime' and 'load average' in output","solution":["uptime"],"success_msg":"你已经会看系统运行时间和负载了。"},{"id":"m4_l3_e2","type":"operation","title":"查看最近命令历史","hint":"history -n 5","success_test":"cmd == 'history -n 5' and output != ''","solution":["history -n 5"],"success_msg":"你已经会利用历史命令回顾操作了。"},{"id":"m4_l3_e3","type":"scenario","question":"为什么排查问题时查看 history 很有价值?","answer":"因为它可以帮助回溯最近做过什么操作,快速定位变更和可能的触发点"}]}
]
},
{
"id": "module_5_service_logs",
"title": "模块 5服务与日志排障",
"summary": "围绕服务启动、运行状态、日志报错和后台执行建立排障链路。",
"lessons": [
{"id":"m5_l1_systemctl","title":"服务管理systemctl 基础","goal":"理解 Linux 服务的查看、启动、停止和重启。","why_it_matters":"现代 Linux 发行版大量使用 systemd 管理服务。","concepts":["服务状态","启动与重启","systemd 基础"],"command":"systemctl","examples":["systemctl status nginx","systemctl restart nginx","systemctl enable nginx"],"pitfalls":["改完配置却忘记重启服务","只看页面,不看服务状态"],"scenarios":["排查服务没起来","改配置后让服务生效"],"exercises":[{"id":"m5_l1_e1","type":"understanding","question":"为什么改完服务配置后常常要 restart 或 reload","answer":"因为配置文件变化不会自动生效,需要让服务重新加载配置"},{"id":"m5_l1_e2","type":"scenario","question":"排查“网站打不开”时,为什么应该先看 systemctl status","answer":"因为要先确认服务是否真的在运行,以及是否有明显启动失败信息"},{"id":"m5_l1_e3","type":"understanding","question":"enable 和 start 的区别是什么?","answer":"start 是当前立即启动enable 是设置开机自动启动"}]},
{"id":"m5_l2_journalctl","title":"看系统日志journalctl","goal":"理解如何查看服务日志和系统日志。","why_it_matters":"很多 systemd 管理的服务排障入口就是 journalctl。","concepts":["单服务日志","最近日志","实时跟踪日志"],"command":"journalctl","examples":["journalctl -u nginx -n 50","journalctl -xe","journalctl -u app -f"],"pitfalls":["只看应用日志,不看 systemd 日志","看太多日志却抓不到最近错误"],"scenarios":["查看服务启动失败原因","查看最近报错"],"exercises":[{"id":"m5_l2_e1","type":"understanding","question":"为什么 journalctl 对 systemd 服务排障特别重要?","answer":"因为它能直接查看服务生命周期和 systemd 记录的日志"},{"id":"m5_l2_e2","type":"scenario","question":"服务启动失败后,下一步除了看 status 还应该看什么?","answer":"看 journalctl -u 服务名 的日志,确认具体报错"},{"id":"m5_l2_e3","type":"understanding","question":"为什么实时排查时常用 -f","answer":"因为 -f 可以持续跟踪新增日志,适合边操作边观察"}]},
{"id":"m5_l3_process_control","title":"进程控制kill / pkill / nohup","goal":"理解如何控制进程和让任务脱离终端运行。","why_it_matters":"部署、排障和临时任务常会遇到进程管理问题。","concepts":["发送信号","按名称结束进程","后台运行"],"command":"kill / pkill / nohup","examples":["kill 1234","pkill nginx","nohup python3 app.py &"],"pitfalls":["直接粗暴 kill 掉关键进程","不知道后台任务输出去哪了"],"scenarios":["结束卡死进程","让脚本后台运行"],"exercises":[{"id":"m5_l3_e1","type":"understanding","question":"为什么 kill 进程前要先确认 PID 和进程身份?","answer":"因为误杀错误进程可能导致服务中断或数据问题"},{"id":"m5_l3_e2","type":"understanding","question":"nohup 的作用是什么?","answer":"让命令在退出终端后继续运行,适合后台任务"},{"id":"m5_l3_e3","type":"scenario","question":"如果你想让一个脚本关掉 SSH 后仍然继续跑,应该想到什么?","answer":"使用 nohup 或其他后台运行方式"}]}
]
},
{
"id": "module_6_network",
"title": "模块 6网络与连接排查",
"summary": "建立 IP、端口、监听、连通性和请求验证等运维网络基础。",
"lessons": [
{"id":"m6_l1_ip_ping","title":"网络基础ip addr / ifconfig / ping","goal":"理解网卡、IP 和连通性的基本概念。","why_it_matters":"服务是否可达,首先是网络问题还是应用问题,需要先分清。","concepts":["网卡","IP 地址","连通性测试"],"command":"ip addr / ifconfig / ping","examples":["ip addr","ifconfig","ping 127.0.0.1"],"pitfalls":["能 ping 通就以为服务一定可用","只会看 IP不理解监听端口"],"scenarios":["确认机器是否有正确 IP","测试目标是否能连通"],"exercises":[{"id":"m6_l1_e1","type":"operation","title":"查看网卡地址","hint":"ip addr","success_test":"cmd == 'ip addr' and 'inet' in output","solution":["ip addr"],"success_msg":"你已经会看基本网卡信息了。"},{"id":"m6_l1_e2","type":"operation","title":"测试本机回环连通性","hint":"ping 127.0.0.1","success_test":"cmd == 'ping 127.0.0.1' and 'packet loss' in output","solution":["ping 127.0.0.1"],"success_msg":"你已经做了一次基础连通性验证。"},{"id":"m6_l1_e3","type":"understanding","question":"为什么 ping 通不等于服务一定可用?","answer":"因为 ping 只说明网络层连通,不代表应用端口和接口层面正常"}]},
{"id":"m6_l2_ss_curl","title":"端口与请求ss / netstat / curl / wget","goal":"建立监听端口和服务请求验证的能力。","why_it_matters":"运维排障很多时候要回答两个问题:端口开没开?接口通不通?","concepts":["端口监听","TCP 层可达性","HTTP 请求验证"],"command":"ss / netstat / curl / wget","examples":["ss -ltnp","netstat -tunlp","curl http://127.0.0.1:8080/health"],"pitfalls":["只看页面打不开,不查监听","只看监听,不测实际请求"],"scenarios":["查服务是否监听端口","测试接口是否返回 200"],"exercises":[{"id":"m6_l2_e1","type":"operation","title":"查看监听端口","hint":"ss -ltnp","success_test":"cmd == 'ss -ltnp' and 'LISTEN' in output","solution":["ss -ltnp"],"success_msg":"你已经会看监听端口了。"},{"id":"m6_l2_e2","type":"operation","title":"请求本地页面","hint":"curl http://127.0.0.1","success_test":"cmd == 'curl http://127.0.0.1' and '<html>' in output","solution":["curl http://127.0.0.1"],"success_msg":"你已经会做基本 HTTP 探测了。"},{"id":"m6_l2_e3","type":"scenario","question":"排查“服务起了但访问失败”时,为什么要同时看 ss 和 curl","answer":"因为 ss 看端口监听curl 看应用层响应,两者结合才能判断问题在哪一层"}]},
{"id":"m6_l3_name_route","title":"路由与名称解析traceroute / dig / whereis 命令定位","goal":"建立链路定位和名称解析基础认知。","why_it_matters":"有些故障不是服务本身坏了,而是路径或解析出了问题。","concepts":["路由路径","DNS 解析","命令位置定位"],"command":"traceroute / dig / which / whereis","examples":["traceroute 8.8.8.8","dig example.com","which curl"],"pitfalls":["把 DNS 问题误判成应用问题","不知道命令来自哪里"],"scenarios":["排查域名异常","确认命令路径和来源"],"exercises":[{"id":"m6_l3_e1","type":"operation","title":"定位 curl 命令路径","hint":"which curl","success_test":"cmd == 'which curl' and '/usr/bin/curl' in output","solution":["which curl"],"success_msg":"你已经会定位命令路径了。"},{"id":"m6_l3_e2","type":"understanding","question":"为什么 DNS 出问题时,服务本身可能没坏但用户仍然访问失败?","answer":"因为域名解析不到正确 IP流量根本到不了目标服务"},{"id":"m6_l3_e3","type":"scenario","question":"排查“域名不通”时除了 curl还应该想到什么","answer":"还应该检查 dig/nslookup 和网络路径,确认是不是解析或链路问题"}]}
]
},
{
"id": "module_7_security",
"title": "模块 7权限、用户与安全基础",
"summary": "围绕用户、组、权限和高风险操作建立 Linux 安全基本认知。",
"lessons": [
{"id":"m7_l1_users","title":"用户与身份whoami / id / passwd / su","goal":"理解当前身份、用户组和密码变更的意义。","why_it_matters":"你是谁、你属于谁、你能做什么,是 Linux 安全的最基础问题。","concepts":["当前用户","用户组","身份切换"],"command":"whoami / id / passwd / su","examples":["whoami","id","passwd"],"pitfalls":["不知道自己当前权限边界","以为所有命令都能执行"],"scenarios":["确认当前身份","看自己属于哪些组"],"exercises":[{"id":"m7_l1_e1","type":"operation","title":"查看当前用户","hint":"whoami","success_test":"cmd == 'whoami' and 'sandbox_user' in output","solution":["whoami"],"success_msg":"你已经会确认当前登录身份了。"},{"id":"m7_l1_e2","type":"operation","title":"查看当前用户组信息","hint":"id","success_test":"cmd == 'id' and 'uid=' in output","solution":["id"],"success_msg":"你已经会查看用户与组信息了。"},{"id":"m7_l1_e3","type":"understanding","question":"为什么运维排障前先确认 whoami 很重要?","answer":"因为不同身份决定你能看到什么、改什么,以及排障时会不会被权限挡住"}]},
{"id":"m7_l2_permissions","title":"权限控制chmod / chown / chgrp","goal":"理解 Linux 权限控制的基本模型和常见修改动作。","why_it_matters":"很多“无法访问、无法执行、无法写入”本质上都是权限问题。","concepts":["读写执行","拥有者与属组","最小权限原则"],"command":"chmod / chown / chgrp","examples":["chmod 644 file.txt","chmod +x run.sh","chown app:app app.log"],"pitfalls":["图省事直接给 777","不了解属组导致协作混乱"],"scenarios":["修脚本执行权限","调整日志文件归属"],"exercises":[{"id":"m7_l2_e1","type":"operation","title":"给文件添加执行权限","hint":"chmod +x /tmp/a/b/c/readme.txt","success_test":"cmd == 'chmod +x /tmp/a/b/c/readme.txt'","solution":["chmod +x /tmp/a/b/c/readme.txt"],"success_msg":"你已经会做最基础的执行权限修改。"},{"id":"m7_l2_e2","type":"understanding","question":"为什么生产环境里不应该随手给 777","answer":"因为 777 让所有人都有读写执行权限,风险过高,容易造成安全和误操作问题"},{"id":"m7_l2_e3","type":"scenario","question":"脚本提示 Permission denied 时,你会先想到什么?","answer":"先检查文件是否有执行权限,以及当前用户是否有访问权限"}]},
{"id":"m7_l3_risk","title":"高风险命令与最小权限原则","goal":"建立运维中“能做”不等于“该做”的安全意识。","why_it_matters":"很多事故不是因为不会,而是因为过度权限和冒险操作。","concepts":["sudo 的边界","危险删除","最小权限"],"command":"sudo / rm -rf / 安全习惯","examples":["sudo systemctl restart nginx","rm -rf /tmp/testdir"],"pitfalls":["把 sudo 当默认前缀","不确认路径就执行递归删除"],"scenarios":["高权限改系统配置","清理目录前先确认路径"],"exercises":[{"id":"m7_l3_e1","type":"understanding","question":"为什么最小权限原则在运维里很重要?","answer":"因为权限越大,误操作和被利用的风险越高,应只给完成任务所需的最小权限"},{"id":"m7_l3_e2","type":"scenario","question":"执行 rm -rf 之前最应该确认什么?","answer":"确认目标路径是否正确,以及是否真的需要递归强制删除"},{"id":"m7_l3_e3","type":"understanding","question":"为什么不应该把 sudo 当成“万能解决方案”?","answer":"因为它绕过权限边界,容易掩盖根因并扩大误操作风险"}]}
]
},
{
"id": "module_8_packages_env",
"title": "模块 8软件包、环境与命令定位",
"summary": "理解命令从哪里来、环境变量如何影响执行、软件包如何管理。",
"lessons": [
{"id":"m8_l1_path_env","title":"环境变量与命令定位env / export / which / whereis","goal":"理解 PATH、环境变量和命令查找机制。","why_it_matters":"很多“命令找不到”“版本不对”“环境不生效”都和环境变量有关。","concepts":["PATH","环境变量","命令来源"],"command":"env / export / which / whereis","examples":["env","export APP_ENV=prod","which python3","whereis nginx"],"pitfalls":["以为命令名唯一对应一个位置","不知道 PATH 顺序会影响执行结果"],"scenarios":["排查命令找不到","排查执行到错误版本"],"exercises":[{"id":"m8_l1_e1","type":"operation","title":"查看环境变量","hint":"env","success_test":"cmd == 'env' and 'PATH=' in output","solution":["env"],"success_msg":"你已经会查看环境变量了。"},{"id":"m8_l1_e2","type":"operation","title":"定位 ls 命令","hint":"which ls","success_test":"cmd == 'which ls' and '/bin/ls' in output","solution":["which ls"],"success_msg":"你已经会查命令来源了。"},{"id":"m8_l1_e3","type":"understanding","question":"为什么 PATH 顺序会影响命令执行结果?","answer":"因为系统会按 PATH 的顺序查找同名命令,先找到哪个就执行哪个"}]},
{"id":"m8_l2_package_mgr","title":"包管理基础apt / yum / dpkg / rpm","goal":"理解 Linux 软件安装与查询的基本方式。","why_it_matters":"软件装没装、版本对不对,是环境排障的重要基础。","concepts":["Debian 与 RedHat 系包管理差异","包查询","版本核对"],"command":"apt / yum / dpkg / rpm","examples":["apt list --installed","yum list installed","rpm -qa | grep nginx"],"pitfalls":["不知道发行版不同,命令体系也不同","只会装包,不会查版本"],"scenarios":["确认软件已安装","核对线上版本"],"exercises":[{"id":"m8_l2_e1","type":"understanding","question":"为什么 apt 和 yum 不能混着理解?","answer":"因为它们属于不同发行版的包管理体系,命令、仓库和包格式都有差异"},{"id":"m8_l2_e2","type":"scenario","question":"排查“命令不存在”时,除了 which 还会想到什么?","answer":"还要确认对应软件包是否已安装,必要时用包管理工具查询"},{"id":"m8_l2_e3","type":"understanding","question":"为什么确认软件版本在运维里很重要?","answer":"因为不同版本的配置、行为和兼容性可能不同,排障和发布都依赖版本信息"}]},
{"id":"m8_l3_alias_habit","title":"alias 与命令行习惯","goal":"建立更高效、更安全的日常命令行习惯。","why_it_matters":"很多效率差异来自长期习惯,而不是单个命令是否会敲。","concepts":["alias","常用缩写","习惯的收益与风险"],"command":"alias","examples":["alias ll='ls -l'","alias gs='git status'"],"pitfalls":["别名过多反而混乱","依赖个人别名导致跨机器不一致"],"scenarios":["提高常用命令效率","统一个人命令习惯"],"exercises":[{"id":"m8_l3_e1","type":"understanding","question":"为什么 alias 既能提升效率,也可能带来问题?","answer":"它能简化命令,但如果过度依赖,换环境或和他人协作时可能造成理解和一致性问题"},{"id":"m8_l3_e2","type":"understanding","question":"为什么运维平台环境中不建议胡乱定义复杂 alias","answer":"因为可能影响命令可预期性,增加排障和协作成本"},{"id":"m8_l3_e3","type":"scenario","question":"什么时候 alias 是好的,什么时候需要克制?","answer":"高频、简单、个人明确的命令可以用 alias涉及生产、协作和高风险操作应尽量保持显式命令"}]}
]
},
{
"id": "module_9_automation",
"title": "模块 9自动化、归档与运维习惯",
"summary": "建立重定向、管道、定时任务、归档备份和命令复盘习惯。",
"lessons": [
{"id":"m9_l1_pipe_redirect","title":"组合能力:管道与重定向","goal":"理解为什么 Linux 强调小命令组合,而不是一个命令包办一切。","why_it_matters":"运维效率往往来自命令组合,而不是单个命令本身。","concepts":["标准输入输出","重定向","管道组合"],"command":"| / > / >>","examples":["grep error /var/log/syslog | wc -l","echo hello > note.txt","cat file >> backup.txt"],"pitfalls":["覆盖写和追加写不分","不会把命令组合成链路"],"scenarios":["统计错误行数","生成结果文件"],"exercises":[{"id":"m9_l1_e1","type":"understanding","question":"为什么管道是 Unix/Linux 的核心思想之一?","answer":"因为它让小工具可以彼此组合,快速拼出解决问题的命令链路"},{"id":"m9_l1_e2","type":"scenario","question":"如果想统计日志里 error 出现了多少次,为什么 grep 配合 wc 很自然?","answer":"因为 grep 负责筛选wc 负责统计,两者分工清晰又容易组合"},{"id":"m9_l1_e3","type":"understanding","question":"> 和 >> 的区别是什么?","answer":"> 是覆盖写入,>> 是追加写入"}]},
{"id":"m9_l2_tar_backup","title":"归档与备份tar / gzip","goal":"理解打包压缩和备份的基本思路。","why_it_matters":"备份不是把文件复制一下,而是要考虑归档、压缩和恢复。","concepts":["归档 vs 压缩","备份与恢复","打包文件"],"command":"tar / gzip","examples":["tar -czf backup.tar.gz /etc","tar -xzf backup.tar.gz -C /tmp"],"pitfalls":["只会备份,不会恢复验证","不知道 tar 和 gzip 各自扮演什么角色"],"scenarios":["备份配置目录","迁移文件集合"],"exercises":[{"id":"m9_l2_e1","type":"understanding","question":"为什么备份后最好做一次恢复验证?","answer":"因为只有验证过能恢复,备份才真正有意义"},{"id":"m9_l2_e2","type":"scenario","question":"为什么很多运维备份会用 tar.gz","answer":"因为它适合把多个文件归档后再压缩,便于传输和保存"},{"id":"m9_l2_e3","type":"understanding","question":"tar 和 gzip 的角色区别是什么?","answer":"tar 负责打包归档gzip 负责压缩"}]},
{"id":"m9_l3_crontab_history","title":"定时任务与操作复盘crontab / history","goal":"理解自动化执行与命令历史复盘的价值。","why_it_matters":"运维很多工作是周期性的,同时排障也离不开复盘。","concepts":["周期任务","命令历史","自动化意识"],"command":"crontab / history","examples":["crontab -l","history -n 10"],"pitfalls":["写了定时任务却不记录输出","不会利用 history 回顾近期操作"],"scenarios":["定时备份","回顾误操作"],"exercises":[{"id":"m9_l3_e1","type":"understanding","question":"为什么定时任务不只要能跑,还要关注日志和输出?","answer":"因为无人值守任务如果失败却没有输出记录,很难排查问题"},{"id":"m9_l3_e2","type":"scenario","question":"复盘线上事故时history 能提供什么帮助?","answer":"帮助确认最近执行过哪些命令,判断是否有变更触发了问题"},{"id":"m9_l3_e3","type":"understanding","question":"为什么自动化不是“偷懒”,而是运维能力的一部分?","answer":"因为自动化能减少重复劳动、降低人为失误并提升稳定性"}]}
]
},
{
"id": "module_10_incidents",
"title": "模块 10运维综合实战场景",
"summary": "把前面所有命令和认知串起来,围绕真实故障场景形成排查链路。",
"lessons": [
{"id":"m10_l1_service_down","title":"场景:服务无法访问排查","goal":"建立“先服务、再端口、再日志、再请求”的排查顺序。","why_it_matters":"这是最经典的运维问题之一。","concepts":["服务状态","端口监听","日志定位","HTTP 验证"],"command":"systemctl / ps / ss / journalctl / curl","examples":["systemctl status nginx","ss -ltnp","curl http://127.0.0.1:8080/health"],"pitfalls":["只看浏览器打不开,不看服务状态","没有层次地乱查"],"scenarios":["应用服务无法访问"],"exercises":[{"id":"m10_l1_e1","type":"scenario","question":"遇到“网站打不开”,一个合理的排查顺序是什么?","answer":"先看服务状态,再看进程和端口,再看日志,最后用 curl 验证接口"},{"id":"m10_l1_e2","type":"understanding","question":"为什么不应该一上来就改配置?","answer":"因为先确认问题在哪一层更重要,盲改配置可能扩大问题"},{"id":"m10_l1_e3","type":"scenario","question":"如果端口没监听,你下一步更应该看什么?","answer":"看服务状态和日志,确认是否启动失败或启动后立即退出"}]},
{"id":"m10_l2_disk_full","title":"场景:磁盘爆满排查","goal":"建立从 df 到 du 再到 find 的磁盘问题定位思路。","why_it_matters":"磁盘满会直接导致服务报错、写入失败和日志异常。","concepts":["文件系统空间","目录占用","大文件定位"],"command":"df / du / find / sort","examples":["df -h","du -sh /var/log","find /var/log -type f"],"pitfalls":["只看 df 不继续追目录","删文件前不确认用途"],"scenarios":["排查磁盘 100%"],"exercises":[{"id":"m10_l2_e1","type":"scenario","question":"磁盘爆满时,为什么通常先 df 再 du","answer":"因为先确认哪个文件系统满了,再定位具体哪个目录占用大"},{"id":"m10_l2_e2","type":"understanding","question":"为什么删除日志前要先确认是否还能用于排障?","answer":"因为日志可能是定位故障的关键证据,盲删会丢失排障线索"},{"id":"m10_l2_e3","type":"scenario","question":"如果 /var/log 特别大,你会想到哪些命令组合?","answer":"df、du、find、sort 组合起来定位大文件和大目录"}]},
{"id":"m10_l3_login_fail","title":"场景:登录失败与权限异常排查","goal":"把身份、权限、日志三者串起来理解。","why_it_matters":"很多系统问题最终都落在权限与身份边界上。","concepts":["当前身份","认证日志","权限边界"],"command":"whoami / id / passwd / grep / tail","examples":["whoami","id","tail -n 20 /var/log/auth.log"],"pitfalls":["只怀疑密码错误,不看日志","忽略组权限问题"],"scenarios":["SSH 登录失败","执行权限不足"],"exercises":[{"id":"m10_l3_e1","type":"scenario","question":"排查登录失败时,除了用户名密码,还要想到什么?","answer":"要看认证日志、用户身份、组信息和权限配置"},{"id":"m10_l3_e2","type":"understanding","question":"为什么权限异常常常不能只靠肉眼猜?","answer":"因为真实问题可能同时涉及用户、组、文件权限和服务身份,需要结合命令验证"},{"id":"m10_l3_e3","type":"scenario","question":"如果脚本明明存在却执行不了,你会从哪几类信息开始看?","answer":"先看 whoami/id再看文件权限和属主属组必要时看相关日志"}]}
]
}
]
}

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Linux 系统学习平台</title>
<title>Linux 运维全场景学习平台</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
@@ -185,8 +185,8 @@
<header class="header">
<div class="header-inner">
<div class="brand">
<h1>🐧 Linux 系统学习平台</h1>
<p>以知识理解为中心,练习为辅,帮助建立真正可迁移的 Linux 能力。</p>
<h1>🐧 Linux 运维全场景学习平台</h1>
<p>以知识理解为中心,尽量覆盖运维强相关全场景,帮助建立真正可迁移的 Linux 能力。</p>
</div>
<div class="header-actions">
<button class="chip-btn active" onclick="setTheme('light')">浅色</button>
@@ -213,10 +213,10 @@
<main class="content card">
<section class="hero" id="heroPanel">
<h2>把 Linux 学明白,再去练</h2>
<h2>建立运维视角,再去学命令</h2>
<p>
这个版本不再以“闯关感”作为核心,而是把 Linux 当成一门真正要学懂的技能来组织
每个课时会先说明为什么重要、核心知识点是什么、常见误区在哪里,再给最小示例和少量练习
这个版本不再把 Linux 做成“命令闯关页”,而是尽量按运维全场景组织课程
从文件系统、日志、资源、服务、网络、权限,到包管理、自动化、综合排障,逐步建立完整认知
</p>
<div class="hero-actions">
<button class="btn btn-primary" onclick="openFirstLesson()">从第一课开始</button>
@@ -273,9 +273,9 @@
<div class="aside-card">
<h3>学习建议</h3>
<ul>
<li>先理解“命令解决什么问题”,再记参数。</li>
<li>不要一开始背太多选项,先掌握最常用组合</li>
<li>日志、配置、目录、进程,是 Linux 学习的大核心场景。</li>
<li>先理解“场景里为什么需要这个命令”,再记参数。</li>
<li>不要只学单个命令,要学命令之间如何串成排障链路</li>
<li>目录、日志、资源、服务、网络、权限,是 Linux 运维学习的大核心场景。</li>
</ul>
</div>
<div class="aside-card">