[{"content":"这里用于记录平时遇到的一些细微但很有用的编程知识点。后续会按照日期不断追加内容。\n2026-04-28 C++ 输入流与格式输出小技巧 1. cin \u0026gt;\u0026gt; noskipws 的使用与回车符处理\nnoskipws 是一个流操纵符，用于告诉 cin 不要跳过空白符（例如空格、换行）。如果不使用它，cin 默认会忽略掉空白字符。 cin.ignore(1000, '\\n')：可以忽略输入缓冲区中的字符，直到遇到换行符 \\n 或达到指定数量（如1000），常用于将前文残留的回车符丢弃掉。 注意：切换为 noskipws 之后，在后续不需要提取空白符的地方，记得使用 skipws 切换回来。 示例代码：\nfor(int i = 1; i \u0026lt;= n; i++){ cin \u0026gt;\u0026gt; noskipws \u0026gt;\u0026gt; T[i].value; cin \u0026gt;\u0026gt; skipws \u0026gt;\u0026gt; T[i].weight; cin.ignore(1000, \u0026#39;\\n\u0026#39;); } 2. 左对齐输出格式化\n使用 std::left 配合 std::setw(5) 可以很方便地实现输出内容左侧对齐并且占用固定字符宽度： cout \u0026lt;\u0026lt; left \u0026lt;\u0026lt; setw(5) \u0026lt;\u0026lt; value; 3. Windows 下 C++ 控制台输出汉字乱码解决\n当使用 C++ 在 Windows 控制台打印中文字符时，容易出现乱码。可以引入 \u0026lt;windows.h\u0026gt;，并将控制台输入输出的编码页设定为 UTF-8（65001）：\n#include \u0026lt;iostream\u0026gt; #include \u0026lt;windows.h\u0026gt; int main() { // 设置控制台输出和输入为 UTF-8 (65001) SetConsoleOutputCP(65001); SetConsoleCP(65001); // 你的逻辑... std::cout \u0026lt;\u0026lt; \u0026#34;按先序输入...\u0026#34; \u0026lt;\u0026lt; std::endl; return 0; } 2026-05-29 C++ string::rfind 逆向查找 rfind 是 std::string 的成员函数，功能与 find 相反——从字符串的末尾开始向前查找子串或字符。\n基本语法：\nsize_t rfind(const string\u0026amp; str, size_t pos = npos) const; // 查找子串 size_t rfind(const char* s, size_t pos = npos) const; // 查找 C 风格字符串 size_t rfind(char c, size_t pos = npos) const; // 查找单个字符 返回匹配的第一个字符的位置索引（从 0 开始） 若未找到，返回 string::npos pos：搜索截至位置，默认为 npos（即从末尾往前搜索整个字符串） 与 find 的关键区别：\n方法 搜索方向 适用场景 find 从左到右 查找第一次出现的位置 rfind 从右到左 查找最后一次出现的位置 实用示例：\n#include \u0026lt;iostream\u0026gt; #include \u0026lt;string\u0026gt; using namespace std; int main() { string path = \u0026#34;/home/user/docs/file.txt\u0026#34;; // 1. 提取文件名（找到最后一个 \u0026#39;/\u0026#39;） size_t pos = path.rfind(\u0026#39;/\u0026#39;); if (pos != string::npos) { string filename = path.substr(pos + 1); cout \u0026lt;\u0026lt; \u0026#34;文件名: \u0026#34; \u0026lt;\u0026lt; filename \u0026lt;\u0026lt; endl; // 输出: file.txt } // 2. 提取文件扩展名 pos = path.rfind(\u0026#39;.\u0026#39;); if (pos != string::npos) { string ext = path.substr(pos); cout \u0026lt;\u0026lt; \u0026#34;扩展名: \u0026#34; \u0026lt;\u0026lt; ext \u0026lt;\u0026lt; endl; // 输出: .txt } // 3. 限制搜索范围：只在前半段查找 string text = \u0026#34;abaaba\u0026#34;; pos = text.rfind(\u0026#34;ab\u0026#34;, 3); // 在位置 0~3 范围内从右往左找 cout \u0026lt;\u0026lt; \u0026#34;前半段中最后一个 ab 在: \u0026#34; \u0026lt;\u0026lt; pos \u0026lt;\u0026lt; endl; // 输出: 3 // 4. 找不到的情况 pos = text.rfind(\u0026#34;xyz\u0026#34;); if (pos == string::npos) { cout \u0026lt;\u0026lt; \u0026#34;未找到子串\u0026#34; \u0026lt;\u0026lt; endl; } return 0; } 常见用途：\n解析文件路径（提取文件名、目录名） 获取文件扩展名 从 URL 中提取最后一段 在长字符串中定位最后一个关键词出现的位置 注意陷阱：\nrfind 返回的索引仍然是从字符串开头数的位置，不是从末尾数的位置 rfind 查找子串时，子串本身的字符顺序不变（仍然是正向匹配），只是搜索方向是从右往左 ","date":"2026-05-29T00:00:00Z","permalink":"/post/micro-knowledge/","title":"📌 细小知识记录"},{"content":"std::min_element 和 std::max_element 是 \u0026lt;algorithm\u0026gt; 头文件中用于在容器中查找最小/最大元素的函数模板。\n函数签名 template\u0026lt;class ForwardIt\u0026gt; ForwardIt min_element(ForwardIt first, ForwardIt last); template\u0026lt;class ForwardIt, class Compare\u0026gt; ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp); template\u0026lt;class ForwardIt\u0026gt; ForwardIt max_element(ForwardIt first, ForwardIt last); template\u0026lt;class ForwardIt, class Compare\u0026gt; ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp); 返回指向最小/最大元素的迭代器 区间为 [first, last)，即左闭右开 如果区间为空，返回 last 如果多个元素并列，返回第一个遇到的最值 min_element — 找最小值 #include \u0026lt;iostream\u0026gt; #include \u0026lt;vector\u0026gt; #include \u0026lt;algorithm\u0026gt; int main() { std::vector\u0026lt;int\u0026gt; v = {3, 1, 4, 1, 5, 9, 2, 6}; auto it = std::min_element(v.begin(), v.end()); if (it != v.end()) { std::cout \u0026lt;\u0026lt; \u0026#34;最小值: \u0026#34; \u0026lt;\u0026lt; *it \u0026lt;\u0026lt; std::endl; // 1 std::cout \u0026lt;\u0026lt; \u0026#34;位置: \u0026#34; \u0026lt;\u0026lt; (it - v.begin()) \u0026lt;\u0026lt; std::endl; // 1（第一个 1） } return 0; } max_element — 找最大值 auto it = std::max_element(v.begin(), v.end()); if (it != v.end()) { std::cout \u0026lt;\u0026lt; \u0026#34;最大值: \u0026#34; \u0026lt;\u0026lt; *it \u0026lt;\u0026lt; std::endl; // 9 std::cout \u0026lt;\u0026lt; \u0026#34;位置: \u0026#34; \u0026lt;\u0026lt; (it - v.begin()) \u0026lt;\u0026lt; std::endl; // 5 } 同时找最小和最大：minmax_element（C++11） 用 minmax_element 一次遍历同时找到最小和最大，效率比分别调用两次更高：\n#include \u0026lt;algorithm\u0026gt; std::vector\u0026lt;int\u0026gt; v = {3, 1, 4, 1, 5, 9, 2, 6}; auto [min_it, max_it] = std::minmax_element(v.begin(), v.end()); std::cout \u0026lt;\u0026lt; \u0026#34;最小值: \u0026#34; \u0026lt;\u0026lt; *min_it \u0026lt;\u0026lt; std::endl; // 1 std::cout \u0026lt;\u0026lt; \u0026#34;最大值: \u0026#34; \u0026lt;\u0026lt; *max_it \u0026lt;\u0026lt; std::endl; // 9 C++17 结构化绑定让写法更简洁。返回 std::pair，.first 是最小迭代器，.second 是最大迭代器。\n自定义比较器 通过第三个参数传入自定义比较函数，实现按特定规则查找：\n// 按绝对值找最小 std::vector\u0026lt;int\u0026gt; v = {-5, 2, -3, 8, -1}; auto it = std::min_element(v.begin(), v.end(), [](int a, int b) { return std::abs(a) \u0026lt; std::abs(b); }); // *it == -1 // 按字符串长度找最长 std::vector\u0026lt;std::string\u0026gt; words = {\u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;cherry\u0026#34;, \u0026#34;date\u0026#34;}; auto longest = std::max_element(words.begin(), words.end(), [](const std::string\u0026amp; a, const std::string\u0026amp; b) { return a.size() \u0026lt; b.size(); }); // *longest == \u0026#34;banana\u0026#34; 注意：比较器应实现严格弱序（strict weak ordering），即 comp(a, b) 返回 true 表示 \u0026ldquo;a 排在 b 前面\u0026rdquo;（a 比 b 更小）。\n普通数组也可以用 迭代器接口使它们兼容 C 风格数组：\nint arr[] = {3, 1, 4, 1, 5, 9, 2, 6}; size_t n = sizeof(arr) / sizeof(arr[0]); auto min_it = std::min_element(arr, arr + n); auto max_it = std::max_element(arr, arr + n); std::cout \u0026lt;\u0026lt; \u0026#34;最小值: \u0026#34; \u0026lt;\u0026lt; *min_it \u0026lt;\u0026lt; std::endl; std::cout \u0026lt;\u0026lt; \u0026#34;最大值: \u0026#34; \u0026lt;\u0026lt; *max_it \u0026lt;\u0026lt; std::endl; min / max / minmax — 比较两个值 std::min 和 std::max 用于两个值之间的比较，与 min_element/max_element（区间内查找）不同：\nint a = 5, b = 3; int smaller = std::min(a, b); // 3 int larger = std::max(a, b); // 5 // 带比较器的版本 int abs_min = std::min(-5, 3, [](int x, int y) { return std::abs(x) \u0026lt; std::abs(y); }); // 3 // C++11: minmax 返回 pair auto [lo, hi] = std::minmax(a, b); // lo=3, hi=5 min_element vs min：区别对照 函数 作用 参数 返回值 std::min(a, b) 两个值取较小 两个值 较小值的引用 std::min_element(first, last) 区间内找最小 迭代器范围 指向最小值的迭代器 常见陷阱 区间为空 std::vector\u0026lt;int\u0026gt; empty; auto it = std::min_element(empty.begin(), empty.end()); if (it == empty.end()) { // 必须检查，否则解引用空迭代器是未定义行为 } 误用 end() 而非 begin() auto it = std::min_element(v.end(), v.begin()); // 错误！first \u0026gt; last，未定义行为 比较器不满足严格弱序 // 错误：缺了相等情况的处理 std::min_element(v.begin(), v.end(), [](int a, int b) { return a \u0026lt;= b; }); // 正确 std::min_element(v.begin(), v.end(), [](int a, int b) { return a \u0026lt; b; }); XX 总结 函数 用途 头文件 min_element 区间内找最小值 \u0026lt;algorithm\u0026gt; max_element 区间内找最大值 \u0026lt;algorithm\u0026gt; minmax_element 区间内同时找最小和最大 \u0026lt;algorithm\u0026gt; min 两个值取较小 \u0026lt;algorithm\u0026gt; max 两个值取较大 \u0026lt;algorithm\u0026gt; minmax 两个值同时取较小和较大 \u0026lt;algorithm\u0026gt; 记住：min_element / max_element 返回迭代器（需要解引用），min / max 返回引用（直接使用）。区间为空时必须检查返回值是否等于 last。\n","date":"2026-05-29T00:00:00Z","permalink":"/post/min-max-element/","title":"C++ 中 std::min_element / std::max_element 用法详解"},{"content":"std::string::npos 是 C++ 标准库中 std::string 类的一个静态常量，常用于字符串查找操作的结果判断。\n定义与值 static const size_type npos = -1; 类型是 std::string::size_type（通常是 size_t） 值为 size_t(-1)，即无符号整数的最大值 32 位系统上为 4294967295 64 位系统上为 18446744073709551615 主要用途：查找失败判断 最常见的用法是作为 find()、rfind()、find_first_of() 等查找函数的返回值，表示\u0026quot;未找到\u0026quot;：\n#include \u0026lt;iostream\u0026gt; #include \u0026lt;string\u0026gt; int main() { std::string s = \u0026#34;hello world\u0026#34;; size_t pos = s.find(\u0026#34;xyz\u0026#34;); if (pos == std::string::npos) { std::cout \u0026lt;\u0026lt; \u0026#34;未找到匹配子串\u0026#34; \u0026lt;\u0026lt; std::endl; } return 0; } 禁忌：不要用 int 接收返回值 一个常见陷阱是用 int 而非 size_t 接收 find() 的返回值：\n// 错误示例 int pos = s.find(\u0026#34;xyz\u0026#34;); // int 无法表示 npos 的全部值域 if (pos == std::string::npos) // 64 位下可能永远为 false 因为 npos 在 64 位系统上是 18446744073709551615，而 int 最大值只有 2147483647，转换后会截断，导致永远不等于 npos。\n正确做法：\nsize_t pos = s.find(\u0026#34;xyz\u0026#34;); // 使用正确的类型 if (pos == std::string::npos) { // 处理未找到 } 也可以使用 C++17 的 auto：\nauto pos = s.find(\u0026#34;xyz\u0026#34;); if (pos == std::string::npos) { ... } find / rfind 详解 find 和 rfind 是最常用的两个字符串查找成员函数，都返回匹配位置或 npos。\nfind — 从前往后找 size_type find(const string\u0026amp; str, size_type pos = 0) const; size_type find(const char* s, size_type pos = 0) const; size_type find(const char* s, size_type pos, size_type n) const; // 查找 s 的前 n 个字符 size_type find(char c, size_type pos = 0) const; 第二个参数 pos 指定从哪个位置开始搜索：\nstd::string s = \u0026#34;hello world, hello again\u0026#34;; auto p1 = s.find(\u0026#34;hello\u0026#34;); // 从 0 开始 → 0 auto p2 = s.find(\u0026#34;hello\u0026#34;, 1); // 从下标 1 开始 → 13（第二个 hello） auto p3 = s.find(\u0026#34;world\u0026#34;); // → 6 auto p4 = s.find(\u0026#34;xyz\u0026#34;); // → npos rfind — 从后往前找 size_type rfind(const string\u0026amp; str, size_type pos = npos) const; size_type rfind(const char* s, size_type pos = npos) const; size_type rfind(const char* s, size_type pos, size_type n) const; size_type rfind(char c, size_type pos = npos) const; pos 默认是 npos（从末尾开始找），返回最后一次出现的位置：\nstd::string s = \u0026#34;hello world, hello again\u0026#34;; auto p1 = s.rfind(\u0026#34;hello\u0026#34;); // → 13（最后一个 hello） auto p2 = s.rfind(\u0026#34;hello\u0026#34;, 12); // 在下标 12 之前找 → 0 auto p3 = s.rfind(\u0026#34;world\u0026#34;); // → 6 auto p4 = s.rfind(\u0026#34;xyz\u0026#34;); // → npos 典型模式：提取文件扩展名 std::string filename = \u0026#34;example.tar.gz\u0026#34;; auto dot = filename.rfind(\u0026#39;.\u0026#39;); if (dot != std::string::npos) { std::string ext = filename.substr(dot); // \u0026#34;.gz\u0026#34; } 用 rfind 而非 find 能正确取到最后一个 .，避免误取中间的扩展名。\nfind_first_of / find_last_of — 查找字符集合 std::string s = \u0026#34;hello:world-example\u0026#34;; auto p1 = s.find_first_of(\u0026#34;:-\u0026#34;); // → 5（第一个 \u0026#39;:\u0026#39;） auto p2 = s.find_last_of(\u0026#34;:-\u0026#34;); // → 11（最后一个 \u0026#39;-\u0026#39;） 其他相关用法 作为参数表示\u0026quot;直到末尾\u0026quot; std::string 的部分成员函数用 npos 表示\u0026quot;剩余全部内容\u0026quot;：\nstd::string s = \u0026#34;hello world\u0026#34;; std::string sub = s.substr(6); // 从 pos 6 到末尾 → \u0026#34;world\u0026#34; std::string sub2 = s.substr(6, 5); // 从 pos 6 取 5 个字符 → \u0026#34;world\u0026#34; std::string sub3 = s.substr(6, std::string::npos); // 显式表示到末尾 → \u0026#34;world\u0026#34; erase 配合 npos s.erase(5, std::string::npos); // 删除从 pos 5 到末尾的所有字符 延伸：vector 也有 npos 吗？ std::vector 没有 npos 成员，因为 vector 没有 find() 成员函数（需用 \u0026lt;algorithm\u0026gt; 的 std::find）。npos 是 std::basic_string 及其特化（string、wstring、u8string 等）特有的。\n总结 要点 说明 值 size_t(-1)，即无符号整型最大值 类型 std::string::size_type（通常为 size_t） 用途 字符串查找失败返回值 find 从前往后找，pos 参数指定起始位置 rfind 从后往前找，pos 参数指定搜索截止位置 find_first_of 查找字符集合中任一字符首次出现的位置 find_last_of 查找字符集合中任一字符最后出现的位置 坑 不要用 int 接收查找结果 适用 std::string 及所有 std::basic_string 特化 ","date":"2026-05-29T00:00:00Z","permalink":"/post/string-npos/","title":"C++ 中 std::string::npos 详解"},{"content":"在 C 语言的数据结构学习中，我们往往会定义带有自身指针的结构体（例如链表的节点）。但如果写成下面这样的代码，编译器就会报错：\ntypedef struct { BiTree data; struct BiQNode *next; } BiQNode; 报错原因分析 在 C 语言中，编译器的解析顺序是严格从上到下的，这就导致了上述代码存在两个致命问题：\n别名尚未定义：当解析到 struct BiQNode *next; 这一行时，编译器还不知道 BiQNode 是什么。因为作为类型的别名，BiQNode 要等到最后一行大括号结束时才会被完整定义。 标签 (Tag) 不存在：上面的代码省略了 struct 后面的标签名。对于编译器而言，struct BiQNode 是一个完全陌生、从未见过的类型，因此无法通过编译。 正确的写法 如果你需要定义包含自身类型指针的结构体（例如链表节点），你必须给结构体起一个“标签名（Tag）”，或者提前声明别名。以下提供两种标准的解决方案。\n方案 A：最稳妥的教科书写法（推荐） 这是最常见、也最不容易出错的写法。我们同时指定标签名和别名，都叫 BiQNode。\ntypedef struct BiQNode { BiTree data; struct BiQNode *next; // 这里必须使用带标签名的完整形式 struct BiQNode } BiQNode; // 此时定义了别名 BiQNode 方案 B：先定义别名，再定义结构体 这种写法在一些大型 C 语言工程（例如 Linux 内核或部分高级开源库）中比较常见，逻辑上非常清晰：\ntypedef struct BiQNode BiQNode; // 先向编译器声明，BiQNode 是 struct BiQNode 的别名 struct BiQNode { BiTree data; BiQNode *next; // 因为前文已经声明了别名，这里可以直接使用 BiQNode，不需要加 struct }; 总结：在 C 中，typedef 只是给已有类型起了个新名字，并不能创造出魔法。当你要在定义结构体内部引用自己时，务必保证这个类型在解析到引用那一行时是可见且已知的。\n","date":"2026-04-28T00:00:00Z","permalink":"/post/c-struct-typedef/","title":"🐛 C语言中结构体自引用报错原因分析"},{"content":"必备插件 插件 来源 C/C++ Microsoft CMake Tools Microsoft 四步上手 ① Ctrl+Shift+P → CMake: Select a Kit → 选编译器 ② 点击底部 \u0026#34;CMake: [Debug]: Ready\u0026#34; → Configure（生成 build） ③ F7 → Build ④ 点击 ▶ 或 Ctrl+F5 → Run / Debug CMakeLists.txt 最佳实践 推荐写法：\nadd_library(lib_linklist STATIC LinkList/LinkList.cpp) target_include_directories(lib_linklist PUBLIC LinkList) 避免使用全局 include_directories()，改用 target_include_directories() 让每个库管理自己的头文件路径。\n常见问题 问题 解决 找不到头文件 底部栏选对 Configuration，或改 c_cpp_properties.json 找不到编译器 确认 MinGW/GCC/Clang 已加入 PATH No kit selected 先执行 Select a Kit build 混乱 rm -rf build，重新 Configure 快捷键 操作 快捷键 构建 F7 运行 Ctrl+Shift+P → Run Without Debugging 调试 Ctrl+F5 选择 Kit Ctrl+Shift+P → CMake: Select a Kit 编译产物位置： build/ 目录（.exe、.a 库文件都在这）\n","date":"2026-04-28T00:00:00Z","permalink":"/post/vscode-cmake/","title":"🛠️ VSCode 多文件 CMake 编译方法"},{"content":" Command+H ：回到主屏幕\nCommand + Tab ：切换app\nCommand +Space ：搜索\nCommand +O 快速搜索\nCommand +N ：新建笔记\nCommand +W： 关闭当前标签页\nCommand +E ：切换预览编辑模式\nCommand+B ：加粗\nCommand+I ：斜体\nCommand +Z：撤销\nCommand +Backspace 删除一行\nCommand+Shift+Z：恢复\nCommand+Shift+3 ：截图\nCtrl +A 行首\nCtrl+E 行尾\nCtrl+B 向前移动一个字符\nCtrl+F 向后移动一个字符\nCtrl+P上移一行\nCtrl+N 下移一行\nCtrl+O 在插入点后新插入一行\nCtrl+T 交换光标前后字符\nCtrl+K 删除到行尾\nCtrl+H 删除左侧字符\nCtrl+D 删除右侧字符\n","date":"2026-04-25T00:00:00Z","permalink":"/post/ipad-shortcuts/","title":"⌨️ iPad 常用键盘快捷键整理"},{"content":"1. h1元素 HTML 由元素组成。 你将使用的第一个元素是 h1 元素： \u0026lt;h1\u0026gt;Welcome to freeCodeCamp\u0026lt;/h1\u0026gt; 它以一个开始标签（\u0026lt;h1\u0026gt;）开始，以一个结束标签（\u0026lt;/h1\u0026gt;）结束，中间是它将显示的文本。 在你的 Welcome to freeCodeCamp 文本前面添加一个开始标签，后面添加一个结束标签，将其转化为一个 h1 元素。 2. h2元素 h1 元素是网页的主标题，每个页面你应该只使用一个。h2 元素表现子标题。每个页面可以有多个，它们看起来像这样： \u0026lt;h2\u0026gt;This is a subheading.\u0026lt;/h2\u0026gt; HTML 中有六个标题元素： h1 到 h6。 它们用于表明网页各部分的重要性，其中 h1 最为重要，而 h6 则最为次要。 3. p元素 \u0026lt;p\u0026gt;This is a paragraph element.\u0026lt;/p\u0026gt; 4. 空元素 \u0026lt;img\u0026gt; 注意，这个图像元素没有结束标签，也没有任何内容。 空元素不能有任何内容，只有一个开始标签。 有时你会看到使用 / 放在 \u0026gt; 之前的空元素，如下所示： \u0026lt;img /\u0026gt; 许多代码格式化工具（如 Prettier）会选择在空元素中包含 /，HTML 规范指出，/ 的存在 \u0026ldquo;并不标志着开始标记是自闭合的，而且是不必要的，没有任何影响\u0026rdquo;。 在实际开发中，这两种形式你都会见到，因此熟悉它们非常重要。 5.图像元素 如果你要显示图像，则需要在图像元素中包含几个属性。这是一个带有 src 属性的图像元素示例 \u0026lt;img src=\u0026#34;https://cdn.freecodecamp.org/curriculum/cat-photo-app/running-cats.jpg\u0026#34; /\u0026gt; src 属性用于指定图像的位置。 对于图像元素，包含另一个名为 alt 的属性是一种好的实践。 alt 属性用于为图像提供简短的描述性文本。\n这是一个带有 src 和 alt 属性的图像元素示例。尝试通过将 src 值更新为 \u0026quot;https://.freecodecamp.org/curriculum/cat-photo-app/cats.jpg\u0026quot; 来破坏图像。你将看到图像消失，只显示 alt 文本。\n\u0026lt;img src=\u0026#34;https://cdn.freecodecamp.org/curriculum/cat-photo-app/cats.jpg\u0026#34; alt=\u0026#34;Two tabby kittens sleeping together on a couch.\u0026#34; /\u0026gt; 6. 属性 属性是放置在 HTML 元素开始标签内的一个值。 属性提供元素的附加信息，或指定元素的行为方式。 以下是属性的基本语法： \u0026lt;element attribute=\u0026#34;value\u0026#34;\u0026gt;\u0026lt;/element\u0026gt; a元素: 锚点anchor \u0026lt;a href=\u0026#34;https://www.freecodecamp.org/news/\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt;Visit freeCodeCamp\u0026lt;/a\u0026gt; 第一个示例使用了 href 和 target 属性。href 属性指定链接的 URL，target 属性指定打开链接的位置。 将 href=\u0026quot;https://www.freecodecamp.org/news/\u0026quot; 更改为 href=\u0026quot;https://www.freecodecamp.org\u0026quot;。现在，当你点击交互式编辑器中的链接时，你将在新的浏览器标签页中看到 freeCodeCamp 主页。 如果没有 href 属性，链接将无法工作，因为没有目标 URL。所以你必须包含这个 href 属性以使链接生效。target=\u0026quot;_blank\u0026quot; 启用链接在新的浏览器标签（页）中打开。 其他常见的属性有 src 和 alt，或备选属性——分别用于指定图像的来源和为图像提供备选描述性文本。 \u0026lt;input type=\u0026#34;checkbox\u0026#34; checked /\u0026gt; 在上面的示例中，有一个 type 属性设置为 checkbox 的 input 元素。 输入用于从用户处收集数据，type 属性指定了输入的类型。 在本例中，该输入是一个复选框。 You will learn more about how inputs work in the upcoming lessons. checked 属性用于指定默认选中的复选框。 checked 属性不需要值。 如果它存在，则默认选中该复选框。 如果它不存在，复选框将被取消选中。 这被称为布尔属性。 在学习 JavaScript 部分时，你将学习更多有关布尔的知识。 在 HTML 中会遇到几种常见的布尔属性，例如 disabled、readonly 和 required。 这些属性用于指定元素的状态，如禁用、只读或必填。 这是一个默认被禁用的文本 input 元素示例。现在从 input 元素中移除 disabled 属性，你将看到该 input 不再默认被禁用。你现在应该能够点击它并在字段内输入内容。 \u0026lt;input type=\u0026#34;text\u0026#34; disabled\u0026gt; 7.link元素 link 元素用于链接样式表和网站图标等外部资源。 以下是为外部 CSS 文件使用 link 元素的基本语法： \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;./styles.css\u0026#34; /\u0026gt; rel 属性用于指定链接资源与 HTML 文档之间的关系。 在这种情况下，我们需要指定该链接资源为 stylesheet。 将 HTML 和 CSS 分置于不同的文件中被视为最佳实践。 开发人员将使用 link 元素来链接外部 CSS 文件，而不是在 HTML 文档中编写所有内容。 href 属性用于指定外部资源 URL 的位置。 示例中的 dot 后跟一个斜杠，是告诉计算机在当前文件夹或目录中查找 styles.css 文件。 link 元素应放在 head 元素内，如下例所示： \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34; /\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34; /\u0026gt; \u0026lt;title\u0026gt;Examples of the link element\u0026lt;/title\u0026gt; \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;./styles.css\u0026#34; /\u0026gt; \u0026lt;/head\u0026gt; 通常情况下，你会在专业代码库中看到多个 link 元素，它们链接到不同的样式表、字体和图标。 下面是一个使用 link 元素链接到外部 Google 字体 Playwright Cuba 的示例： \u0026lt;link rel=\u0026#34;preconnect\u0026#34; href=\u0026#34;https://fonts.googleapis.com\u0026#34; /\u0026gt; \u0026lt;link rel=\u0026#34;preconnect\u0026#34; href=\u0026#34;https://fonts.gstatic.com\u0026#34; crossorigin /\u0026gt; \u0026lt;link href=\u0026#34;https://fonts.googleapis.com/css2?family=Playwrite+CU:wght@100..400\u0026amp;display=swap\u0026#34; rel=\u0026#34;stylesheet\u0026#34; /\u0026gt; Google 字体是一套免费的开源自定义字体，你可以在任何项目中使用。 你可以选择要使用的字体，Google 会为你提供必要的 HTML 和 CSS 代码。 在这个示例中，rel 属性的 preconnect 值告诉浏览器，要与 href 属性中指定的值提前建立连接。 这样做是为了加快这些外部资源的加载时间。\nlink 元素的另一个常见用例是链接到图标。 下面是一个链接到 favicon 的示例：\n\u0026lt;link rel=\u0026#34;icon\u0026#34; href=\u0026#34;favicon.ico\u0026#34; /\u0026gt; favicon 是 favorite icon（收藏夹图标）的缩写，通常是在浏览器标签（页）中显示在网站标题旁边的小图标。许多网站会使用 favicon 来显示他们的品牌图标。 8. HTML 模板 HTML 模板就像一个现成的网页模板。模板包括每个 HTML 文档所需的基本结构和重要元素。 它可以节省你的时间，并有助于确保你的页面设置正确。 这是一个示例： \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;utf-8\u0026#34; /\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34; /\u0026gt; \u0026lt;title\u0026gt;freeCodeCamp\u0026lt;/title\u0026gt; \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;./styles.css\u0026#34; /\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; 让我们来分析一下这个模板的关键部分。 首先，是 DOCTYPE 声明： \u0026lt;!DOCTYPE html\u0026gt; 它会告诉浏览器你使用的 HTML 版本。 接下来，是 html 标签： \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;!--All other elements go inside here--\u0026gt; \u0026lt;/html\u0026gt; 这包括你所有的内容，并可指定页面语言。 在 html 标记内，你会发现两个主要部分——一个 head 和一个 body： \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;!--Important metadata goes here--\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;!--Headings, paragraphs, images, etc. go inside here--\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; head 部分包含重要的幕后信息： \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34; /\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34; /\u0026gt; \u0026lt;title\u0026gt;Document Title Goes Here\u0026lt;/title\u0026gt; \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;./styles.css\u0026#34; /\u0026gt; \u0026lt;/head\u0026gt; 网站的元数据，包含在 meta 元素中，其中包含字符编码等详细信息，以及 Twitter 等网站应如何预览你的页面链接。 你网站的标题，可在 title 元素中找到，它决定了显示在浏览器标签页或窗口中的文本。 最后，你通常会在 head 部分使用 link 元素链接页面的外部样式表。 body 部分是放置所有内容的地方： \u0026lt;body\u0026gt; \u0026lt;h1\u0026gt;I am a main title\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;Example paragraph text\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; 9.UTF-8 字符编码 UTF-8，或 UCS 转换格式 8，是一种在网络上广泛使用的标准化字符编码。 字符编码是计算机将字符存储为数据的方法。 从本质上讲，网页上的所有文本都是以一个或多个字节形式存储的字符序列。 在计算中，字节是由 8 位或二进制数字组成的数据单位。 UTF-8 支持 Unicode 字符集中的所有字符，包括所有书写系统、语言和技术符号中的字符和符号。 下面是使用带有将字符编码设置为 UTF-8 的 charset 属性的 meta 元素的示例： \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34; /\u0026gt; 通过将字符编码设置为 UTF-8，可确保页面上正确显示重音 \u0026quot;e\u0026quot; 字符（é）。 下面是使用 UTF-8 字符编码的扩展代码示例： \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34; /\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34; /\u0026gt; \u0026lt;title\u0026gt;Examples of the UTF-8 encoding\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;p\u0026gt;Café\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; 对于创建的每个新项目，你都应包含将 charset 属性设置为 UTF-8 的 meta 元素。 10. 注释 \u0026lt;!--`, contains any number of lines of text, and ends with `--\u0026gt; 11. main元素 HTML5 有一些元素能够标识不同的内容区域。 这些元素能让你的 HTML 易于阅读，并有助于搜索引擎优化（SEO）和无障碍。 main 元素用于表示 HTML 文档正文的主要内容。 main 元素里的内容应该是文档中唯一的，不应该在文档的其他部分重复。 \u0026lt;main\u0026gt; \u0026lt;h1\u0026gt;Most important content of the document\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;Some more important content...\u0026lt;/p\u0026gt; \u0026lt;/main\u0026gt; 通过在 h1 元素前添加 \u0026lt;main\u0026gt; 开始标签，并在 p 元素后添加 \u0026lt;/main\u0026gt; 结束标签，来识别此页面的主要部分。 12.ul元素 要创建一个无序项目列表，你可以使用 ul 元素。 li 元素用于在有序或无序列表中创建列表项。 这是一个无序列表中列表项的示例： \u0026lt;ul\u0026gt; \u0026lt;li\u0026gt;milk\u0026lt;/li\u0026gt; \u0026lt;li\u0026gt;cheese\u0026lt;/li\u0026gt; \u0026lt;/ul\u0026gt; 13.figure元素 figure 元素代表自包含的内容，允许你将图像与标题相关联。 图题（figcaption）元素用于添加标题来描述 figure 元素中包含的图像。 这是一个标题为 A cute cat 的 figcaption 的元素示例： \u0026lt;figure\u0026gt; \u0026lt;img src=\u0026#34;image.jpg\u0026#34; alt=\u0026#34;A description of the image\u0026#34;\u0026gt; \u0026lt;figcaption\u0026gt;A cute cat\u0026lt;/figcaption\u0026gt; \u0026lt;/figure\u0026gt; 要强调一个特定的单词或短语，你可以使用 em 元素。 通过将 figcaption 元素中的单词包裹在强调 em 元素中来强调它。 14.ol元素 有序列表（ol）的代码类似于无序列表，但有序列表中的列表项在显示时是编号的。 15.em元素斜体,strong元素加粗 16.footer元素 footer 元素用于定义文档或章节的页脚。 页脚通常包含文档作者信息、版权数据、使用条款链接、联系信息等。 17.Div 元素 div 元素用作容器以分组其他元素。 这是一个 div 元素的示例。为你的 div 元素添加另一个段落元素，并在预览窗口中查看更改。 \u0026lt;div\u0026gt; \u0026lt;p\u0026gt;Example paragraph element.\u0026lt;/p\u0026gt; \u0026lt;/div\u0026gt; 当你想要将一组将共享一组 CSS 样式的超文本标记语言元素分组时，你主要会使用 div 元素。你将在后续的课程和研讨会中学习更多关于 CSS 的内容。 尽管 div 元素在实际代码库中常被使用，你应当小心不要过度使用它。有些时候，使用其他元素会更合适。 例如，如果你想将内容划分为多个部分，那么使用 section 元素比使用 div 元素更合适。 在第一个 section 元素下方添加另一个 section 元素。然后在该 section 元素内添加 h2 和 p 元素。你可以使用任何你喜欢的文本，并且你将在预览窗口中看到更改。 \u0026lt;section\u0026gt; \u0026lt;h2\u0026gt;Mammals\u0026lt;/h2\u0026gt; \u0026lt;p\u0026gt; Mammals are warm-blooded animals with fur or hair. Most give birth to live young. \u0026lt;/p\u0026gt; \u0026lt;ul\u0026gt; \u0026lt;li\u0026gt;Lion\u0026lt;/li\u0026gt; \u0026lt;li\u0026gt;Elephant\u0026lt;/li\u0026gt; \u0026lt;li\u0026gt;Dolphin\u0026lt;/li\u0026gt; \u0026lt;/ul\u0026gt; \u0026lt;/section\u0026gt; section元素相比div元素没有语义而言有语义。语义是语言中单词或短语的含义。 HTML 是一种语言，元素也有自己的语义含义。 因此，这意味着如果你使用了 section 元素， 浏览器将获取其语义含义并理解应将其视为一个独立部分——无论是在台式机上、移动设备上，还是其他任何设备上。 18.ID 和类 id 属性为 HTML 元素添加唯一标识符。 这是一个带有 id 为 title 的 h1 元素示例。 在 h1 元素下方，添加一个 h2 元素，其 id 设置为 \u0026quot;subtitle\u0026quot;。你可以为 h2 编写任意文本，并且你将在预览窗口中看到更改。 \u0026lt;h1 id=\u0026#34;title\u0026#34;\u0026gt;Movie Review Page\u0026lt;/h1\u0026gt; 你可以在你的 JavaScript 或 CSS 中引用 title 的 id 名称。以下是一个 CSS 示例，引用 title 的 id 来将文本 color 更改为 red。 注意：在此交互示例中已为你提供了一些 CSS。不要担心尝试理解这些 CSS 代码，因为你将在后续课程中学习更多相关内容。但如果你想看到文本颜色变为蓝色，点击 styles.css 标签（页），并将 color: red; 改为 color: blue;。 \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;utf-8\u0026#34; /\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34; /\u0026gt; \u0026lt;title\u0026gt;Review page Example\u0026lt;/title\u0026gt; \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;./styles.css\u0026#34; /\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;h1 id=\u0026#34;title\u0026#34;\u0026gt;Movie Review Page\u0026lt;/h1\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; #title { color: red; } 在 title之前的#,告诉计算你你想指向一个拥有对应id的值. id值不能重复. 关于 id 值的另一个需要注意的事情是它们不能有空格。 这是一个是将单词 main 和 heading 应用于一个 id 属性值的示例： \u0026lt;h1 id=\u0026#34;main heading\u0026#34;\u0026gt;Main heading\u0026lt;/h1\u0026gt; 浏览器会将此空格视为 id 的一部分，这将在样式和脚本处理中导致不必要的问题。id 属性值应仅包含字母、数字、下划线和破折号。 与 id 属性不同，class 属性值不需要唯一，可以包含空格。 这是一个将名为 box 的类应用到 div 元素的示例。 \u0026lt;div class=\u0026#34;box\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; 如果你想为一个元素添加多个类名，可以通过空格分隔这些名称来实现。下面是一个将多个类应用到 div 元素的更新示例。 \u0026lt;div class=\u0026#34;box red-box\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; 这是为多个 div 元素应用多个类的另一个示例。 注意：在此交互示例中已为你提供了一些 CSS。不要担心尝试理解 CSS 代码，因为你将在后续课程中学习更多相关内容。点击 styles.css 标签（页），并将 background-color: red; 改为 background-color: black;。 \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;utf-8\u0026#34; /\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34; /\u0026gt; \u0026lt;title\u0026gt;Colored boxes example\u0026lt;/title\u0026gt; \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;./styles.css\u0026#34; /\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div class=\u0026#34;box red-box\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;box blue-box\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;box red-box\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;box blue-box\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; .box { width: 100px; height: 100px; } .red-box { background-color: red; } .blue-box { background-color: blue; } 那么，回顾一下，你什么时候应该使用 id 而不是 class？ 当你希望将一组样式应用于许多元素时，最好使用类。 如果要针对特定的元素，最好使用 id，因为这些值需要是唯一的。\n19.HTML 实体 HTML 实体或字符引用是用于表示 HTML 中保留字符的一组字符。 假设你想在屏幕上显示文本 This is an \u0026lt;img/\u0026gt; element。如果你使用当前编辑器中的代码，它不会显示预期的结果。即使你为示例添加了 src 和 alt 属性，它也会在段落中间显示一张图像，而不是预期的结果。 \u0026lt;p\u0026gt;This is an \u0026lt;img /\u0026gt; element\u0026lt;/p\u0026gt; 当超文本标记语言解析器看到小于号（\u0026lt;）符号后跟一个超文本标记语言标签名称时，它会将其解释为一个超文本标记语言元素。这就是为什么你在屏幕上没有得到期望的 This is an \u0026lt;img/\u0026gt; element 结果。 为了解决此问题，你可以使用超文本标记语言实体。以下是使用正确的超文本标记语言实体表示小于（\u0026lt;）和大于（\u0026gt;）符号的更新示例。现在你应该在屏幕上看到 This is an \u0026lt;img/\u0026gt; element。 \u0026lt;p\u0026gt;This is an \u0026amp;lt;img /\u0026amp;gt; element\u0026lt;/p\u0026gt; \u0026amp;lt;代表\u0026lt; \u0026amp;gt;代表\u0026gt; 这些类型的字符引用被称为命名字符引用。 命名字符引用用(\u0026amp;)开头,用(;)结尾. 通过使用命名字符引用，HTML 解析器不会将其与实际的 HTML 元素混淆。 另一种类型的字符引用是十进制数字引用。 这个字符引用以一个与号和哈希符号（#）开头，后面跟一个或多个十进制数字，后面跟一个分号。 下面是使用小于符号的十进制数字引用的示例。 启用交互式编辑器并更改代码以查看不同的符号。你可以使用 \u0026amp;#169; 表示版权符号，©使用 \u0026amp;#174; 表示注册商标符号。® \u0026lt; 表示\u0026lt; 最后一种类型的字符引用是十六进制数字引用。 这个字符引用以一个与号、哈希符号和字母 x 开头。 然后，后面跟一个或多个 ASCII 十六进制数字，并以分号结束。 这是使用小于符号的十六进制数字引用的示例。 启用交互式编辑器并更改代码以查看不同的符号。你可以使用 \u0026amp;#x20AC; 表示欧元符号€，使用 \u0026amp;#x03A9; 表示希腊大写字母欧米茄符号Ω。\u0026lt; \u0026lt; \u0026amp;是\u0026amp;的转义字符 20. Script元素 下面是一个在超文本标记语言文档中使用 script 元素的示例 \u0026lt;body\u0026gt; \u0026lt;script\u0026gt; // alert(\u0026#34;Welcome to freeCodeCamp\u0026#34;); \u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; 虽然从技术上讲，你可以在 script 标签中编写所有 JavaScript 代码，但最佳实践是链接到外部 JavaScript 文件。 这是一个使用 script 元素链接到外部 JavaScript 文件的例子： \u0026lt;script src=\u0026#34;path-to-javascript-file.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; src标签被用于确定外部JavaScript文件的地址. 不鼓励将所有 JavaScript 放在 HTML 文档中的原因是关注点分离。 关注点分离是一种设计原则，将程序分成不同的部分，每个部分处理一个单独的关注点。 在这种情况下，我们希望将 JavaScript 代码与 HTML 代码分开。 21. 22. 23. 24. 25. ","date":"2026-04-25T00:00:00Z","permalink":"/post/html-responsive/","title":"🌐 HTML (Responsive Web Design Certification) 学习笔记"},{"content":"在今天（也就是2026年4月25日），我终于为自己的个人主页 largeoyos.github.io 添加了完整的博客功能！\n以前我的主页主要是用来导航到各种不同的有趣项目。但一直希望能有一个简单的、轻量级的基于 Markdown 的纯前端动态渲染博客。\n这个博客有哪些功能？ 原生的 Markdown 解析：你看到的加粗、代码块等都是直接从 .md 文件中解析出的。 自动化时间排序：通过一个 posts.json 索引，主页总是显示最新动态。 标签/分类系统：可以快捷过滤想要阅读的技术文章或碎碎念。 未来计划 写更多 CS:APP 的避坑指南 把博客扩展出评论系统 用 AI 让生成博客更加自动化 感谢来到我的数字空间。如果你也是一名 Hacker，欢迎探索！\n","date":"2026-04-25T00:00:00Z","permalink":"/post/hello-world/","title":"🎉 第一篇博客：搭建个人主页的全新博客版块"},{"content":" 可以通过:man 指令名 来⾃⾏了解指令语法 1.nano nano hello.c 完成程序 Ctrl+O保存 Enter确认文件名 Ctrl+X退出nano gcc hello.c -o hello 编译 ./hello运行 2.文件目录篇 以根⽬录算起的绝对路径以 /开头，以家⽬录算起的绝对路径以 ~开头，相对路径不需要 /或 ～开头。\n举例：⼀个名为ustc的⽤⼾在他的家⽬录下创建了⼀个名为os的⽬录，在os⽬录下⾯⼜创建了⼀个名为lab1的⽬录，则该lab1⽬录可以表⽰为： /home/ustc/os/lab1 ~/os/lab1\n如果⼯作⽬录在家⽬录：os/lab1\n如果⼯作⽬录在os⽬录：lab1\nls [参数] [name]\nls / 列出所有根目录 ls *.txt 列出所有txt文件 参数 -a 显示所有文件及目录 -d 只列出目录 -l 长格式,详细解释后面有 -r 逆序排序 -t -A -F -R 递归处理，显示所有目录及子文件 -la等价于 ll ls- lh: (h让total下的数据变成k,m等易于读的大小)\ntotal 4.0K -rw-rw-r-- 1 largeoyos largeoyos 9 Mar 4 16:59 readme.txt -rw-rw-r-- 1 largeoyos largeoyos 0 Mar 4 16:55 study.txt 文件类型: 普通文件:文本文件：ASCII码形式存储，以-开头，如： -rw-r\u0026ndash;r\u0026ndash;1 root root 39599 Mar 8 12:15 x.sh 目录文件：以d开头，如： drwxr-xr-x 2 root root 4096 Aug 2 2006 bin 设备文件 : 块设备文件：以b开头( 硬盘（HDD）固态硬盘（SSD）U盘 SD 卡) brw-rw\u0026mdash;-1 root disk 3, 1 Jan 30 2003 /dev/hda1 字符设备文件：以c开头 (键盘 鼠标 串口（UART）控制台（TTY）打印机。) crw\u0026mdash;\u0026mdash;-1 root root 4, 1 Jul 31 13:49 /dev/tty1 链接文件: 存放文件系统通向文件的路径，以l开头 文件权限\n-rw-rw-r-- (权限控制)： 第一个字符 - 表示这是一个普通文件（如果是 d 则表示目录）。 后面的字符三个一组：rw- (你)、rw- (你所在的组)、r-- (其他人)。 r=读取，w=写入，-=没权限。 1 (链接数)： 表示有多少个文件名指向这个数据块。 largeoyos (所有者)： 表示这个文件属于你（你的用户名）。 largeoyos (所属组)： 表示这个文件属于哪个用户组。 权限 (-rw-rw-r\u0026ndash;) 链接数 所有者 组 大小 修改时间 文件名 文件类型与权限 1 largeoyos largeoyos 0 Mar 4 16:54 readme.txt pwd [\u0026ndash;help] [\u0026ndash;version] pwd 查看当前所在目录 cd 切换工作目录 cd .. 返回上一级目录 cd - 返回上一次所在目录 cd ../../../ 回退三级 mkdir 创建新目录 mkdir -p folder/test (folder目录下建立test文件夹,加了-p参数后,若folder不存在则直接新建) -m 设置目录权限 :mkdir -m 700 3 常见的权限组合表 read:4; write:2;execute:1; 数字 权限位 含义 777 rwxrwxrwx 所有人都能干任何事（很不安全！） 755 rwxr-xr-x 我全能干，别人只能看和进（程序的默认权限） 644 rw-r--r-- 我能读写，别人只能看（普通文件的默认权限） 600 rw------- 只有我能读写（你的 .pem 密钥文件就该设成这样） rmdir 删除空目录 -p 当子目录被删除后使他成为空目录的话则一并删除\nrm 删除一个文件或目录 rm [-rf] name -i 删除前逐一询问确认。 -f 即使原档案属性设为唯读，亦直接删除，无需逐一确认。 -r 将目录及以下之档案亦逐一删除。 删除当前目录下的所有文件及目录，命令行为： rm -r *\ncp复制文件或目录 cp [-r] source dest -r 或 -R：递归复制目录及其内容（用于复制目录）。 -i：交互模式，覆盖前提示用户确认。 -f：强制复制，覆盖目标文件而不提示。 -v：显示详细的复制过程（verbose）。 -p：保留文件的原始属性（如权限、时间戳等）。 -a：归档模式，等同于 -dpR，保留所有文件属性和递归复制目录。 -u：仅当源文件比目标文件新时才复制（更新模式）。 -l：创建硬链接而不是复制文件。 -s：创建符号链接（软链接）而不是复制文件。\nmv 移动或重命名文件或目录 mv source dest -i：覆盖现存文件时提示，建议打开此选项，避免误操作覆盖掉目标文件 -f：不提示直接覆盖存在的目标文件 -n: 不要覆盖任何已存在的文件或目录。 -u：当源文件比目标文件新或者目标文件不存在时，才执行移动操作。 -b: 当目标文件或目录存在时，在执行覆盖前，会为其创建一个备份。\nchmod 改变文件或目录的权限 MODE模式： u：文件所属帐户 g：文件所属组 o：不同组的帐户 a：所有帐户 +：添加权限 -：去除权限 =：使得指定文件只具有这些权限\n使文件file各用户都拥有完全权限： chmod 777 file 允许所有人读file，但只有拥有者能改变它： chmod 644 file 给所有人增加写权： chmod a+w file 对组级和其他用户除去写权和读权： chmod o-wr,g-wr file 建立其他用户的只读权： chmod o=r file 注意控制权限，尽量不要给其他用户修改删除文件等权限 ln :为某一个文件在另外一个位置建立一个同步的链接 ln -s /目标文件夹的完整路径 /快捷方式存放的路径 -s 代表软连接\nlsblk 查看磁盘样貌\nNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 73.9M 1 loop /snap/core22/2045 loop1 7:1 0 4K 1 loop /snap/bare/5 loop2 7:2 0 245.1M 1 loop /snap/firefox/6565 loop3 7:3 0 251.6M 1 loop /snap/firefox/7836 loop4 7:4 0 16.4M 1 loop /snap/firmware-updater/216 loop5 7:5 0 516M 1 loop /snap/gnome-42-2204/202 loop6 7:6 0 18.5M 1 loop /snap/firmware-updater/210 loop7 7:7 0 91.7M 1 loop /snap/gtk-common-themes/1535 loop8 7:8 0 10.8M 1 loop /snap/snap-store/1270 loop9 7:9 0 49.3M 1 loop /snap/snapd/24792 loop10 7:10 0 48.1M 1 loop /snap/snapd/25935 loop11 7:11 0 576K 1 loop /snap/snapd-desktop-integration/315 loop12 7:12 0 576K 1 loop /snap/snapd-desktop-integration/343 sda 8:0 0 60G 0 disk ├─sda1 8:1 0 1M 0 part └─sda2 8:2 0 60G 0 part / sr0 11:0 1 5.9G 0 rom /media/largeoyos/Ubuntu 24.04.3 LTS amd64 sda:物理磁盘 sda1:用于引导系统 后面的依次叫sdb\u0026hellip; RO:只读 RM:可插拔 根目录文件详解 bin home mnt sbin.usr-is-merged usr bin.usr-is-merged lib opt snap var boot lib64 proc srv cdrom lib.usr-is-merged root swap.img dev lost+found run sys etc media sbin tmp 1. 核心居住区（你最常打交道的） /home：这是你的私人领地。 你的桌面、下载、文档全都存在这里。 /root：超级管理员的家。 它是系统老大（root 用户）的私人房间。 /tmp：临时存放处。 软件运行时产生的临时垃圾会扔在这里，通常系统重启后这里会被清空。 2. 系统核心区（相当于大楼的配电室和承重墙） /bin \u0026amp; /sbin：命令存放地。 ls, cd, cp 等基本命令就住在这里。带有 s 的（sbin）通常是给管理员用的高级命令。 /etc：配置中心。 所有的系统设置文件（比如网络配置、软件选项）都放在这。想改系统设置，通常就是改这里的某个文件。 /boot：启动区。 存放 Linux 内核和启动引导程序（GRUB）。没事别动它，动了系统可能就起不来了。 /usr：软件安装区。 你以后安装的大部分用户级软件（像浏览器、播放器）的代码和数据都在这。 3. 设备与硬件区（Linux 的“黑科技”） /dev：设备文件夹。 在 Linux 看来，“一切皆文件”。你的硬盘、鼠标、键盘在这里都被映射成一个文件。 /media \u0026amp; /mnt：外部设备挂载点。 你插个 U 盘或者挂载第二个硬盘，它们的内容就会显示在这里。 /proc \u0026amp; /sys：虚拟文件夹。 它们不占用硬盘空间，而是内存里运行状态的实时反馈。比如你想看 CPU 信息，其实就是在读这里的文件。 4. 特殊文件 swap.img：虚拟内存文件。 当你的物理内存不够用时，系统会把一部分硬盘当内存使。那个红叉是因为这个文件正在被系统锁定使用，普通人不能随便读写。 3.文件控制 echo 将文本输出到标准输出 echo \u0026ldquo;Hello World\u0026rdquo; 显示字符串 echo 内容\u0026raquo;test.txt 追加内容进test.txt cat 将文件内容输出到屏幕 touch xxx.txt :新建txt文件 vim xxx.txt :创建后同时用vim打开 4.进程控制 kill -l：列出所有可用的信号。 -s：发送特定的信号给目标进程，如 -9 表示发送 KILL 信号，即强制终止进程。 常用的几个信号: SIGKILL（信号9）：立即结束进程，不能被捕获或忽略。 SIGTERM（信号15）：正常结束进程，可以被捕获或忽略。 SIGSTOP（信号19）：暂停进程，不能被捕获、忽略或结束。 SIGCONT（信号18）：继续执行被暂停的进程。 SIGINT（信号2）：通常是Ctrl+C产生的信号，可以被进程捕获或忽略。 如kill -9 686 ps :任务管理器 ps: 显示当前用户在当前终端控制下的进程。考虑到用户通常想看不止当前用户和当前终端下的进程，所以不加参数的用法并不常用。 ps aux: 展示所有用户所有进程的详细信息。注意，a前面带一个横线是严格意义上不正确的使用方法。 ps -ef: 也是展示所有用户所有进程的详细信息。就输出结果而言和ps aux无甚差别。 shutdown -h now: Close the service hostname: Check the name of the host 5. 通配符和输出过滤 ? 通配符 :代表一个字符 *通配符 :代表任意个字符 [n1-n2]通配符 : 指定查询范围，n1 n2代表任意数字或字母 ls [a-z]* 6. 安装命令 apt sudo apt update 刷新电脑上的软件清单,看看有没有新版本的软件可以用\nsudo apt install xxx :安装xxx应用\nsudo apt remove xxx :卸载xxx应用\nsudo apt-get install xxx -y :不带进度条的安装,常用于脚本,以保证输出格式\nsudo software-properties-gtk 打开\u0026quot;软件与更新\u0026quot;程序\nsudo apt install open-vm-tools-desktop 安装VMware Tools 工具\ndisk 或gparted是磁盘工具\nwegt wget是一个在命令行下下载文件的工具。常见的使用方法是：wget [-O FILE] URL\n例如，我们要下载 https://git-scm.com/images/logo@2x.png 到本地。\n直接下载：wget https://git-scm.com/images/logo@2x.png，文件名是logo@2x.png。 直接下载并重命名：wget -O git.png https://git-scm.com/images/logo@2x.png，文件名是git.png。注：-O中的O表示字母O而不是数字0。 注意，如果发现有同名文件，1所示方法会在文件名后面加上.1的后缀进行区分，而2所示方法会直接覆盖。 wget -O ./personal_file/git.png https://git-scm.com/images/logo@2x.png 改变目录这样写\n7. 网络命令 ping -c 4 192.168.119.1\n-c 限制次数 4是次数 ip add: Check the ip address curl ifconfig.me :查询公网ip curl -4 ifconfig.me :强制查询ipv4地址 1: lo: \u0026lt;LOOPBACK,UP,LOWER_UP\u0026gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever 2: eth0@if2919: \u0026lt;BROADCAST,MULTICAST,UP,LOWER_UP\u0026gt; mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether bc:24:11:70:94:ab brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.31.55.232/16 brd 172.31.255.255 scope global eth0 valid_lft forever preferred_lft forever inet6 2001:da8:d800:4bfc:be24:11ff:fe70:94ab/64 scope global dynamic mngtmpaddr noprefixroute valid_lft 86398sec preferred_lft 14398sec inet6 fe80::be24:11ff:fe70:94ab/64 scope link valid_lft forever preferred_lft forever 1. lo (Loopback / 回环网卡) 这是虚拟的“本地网卡”，专门用于机器自己跟自己通信。 关键地址： 127.0.0.1 (IPv4) 和 ::1 (IPv6)。 用途： 无论你是否插网线，这个网卡永远存在。当你运行 Nginx 并在服务器本机输入 curl 127.0.0.1 时，流量走的就是这个网卡。 状态： UNKNOWN 在这里是正常的。 2. eth0 (Ethernet / 以太网卡) 这是你的主网卡，负责服务器与外界（互联网或其他服务器）的通信。 内网 IP 地址： 172.31.55.232 这是一个私有 IP。如果你的服务器在阿里云、腾讯云或校园网内，这是它在局域网里的身份。 IPv6 地址： 2001:da8:... 这是一个公网 IPv6 地址。如果你的网络环境支持 IPv6，别人可以通过这个长地址直接访问你的 Nginx。 MAC 地址： bc:24:11:70:94:ab 这是网卡的物理硬件唯一标识。 状态： UP 表示网卡正在工作且已连接。 3. 重点总结：哪个地址最有用？ 如果你在服务器本机测试 Nginx：请访问 127.0.0.1。 如果你在同一局域网的其他机器访问这台服务器：请访问 172.31.55.232。 如果你想从外网（家里）访问这台服务器： 通常需要一个公网 IP（在云服务的管理后台可以看到，通常不直接显示在这个列表里，因为它是通过 NAT 映射的）。 或者尝试使用那个以 2001 开头的 IPv6 地址（前提是你家里的网络也支持 IPv6）。 8. 配置python环境 再次进入 source myenv/bin/activate 再次退出 deactivate 快速找回 find ~ -name \u0026ldquo;activate\u0026rdquo; -type f\n9.Nginx sudo apt install nginx 安装并且自动启动 本机用localhost进入,windows用 http://192.168.119.129 练习服务管理： 你可以学习如何开启、关闭、重启服务：\n按下键盘上的 q 键即可回到命令行输入状态。 操作 命令 启动 sudo systemctl start nginx 停止 sudo systemctl stop nginx 重启 (应用重大更改) sudo systemctl restart nginx 重载 (无缝应用配置更改) sudo systemctl reload nginx 开机自启 sudo systemctl enable nginx 检查状态 sudo systemctl status nginx 查看端口占用： ss -tunlp | grep 80 这会告诉你 80 端口（HTTP 默认端口）是否被 Nginx 占用了。\ntcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:* tcp LISTEN 0 511 [::]:80 [::]:*\n1. 命令在查什么？ ss：查看系统的网络套接字（Sockets）统计信息。 -tunlp：这是一个组合参数： t: 显示 TCP 连接（网页浏览通常用 TCP）。 u: 显示 UDP 连接。 n: 直接显示端口号（如 80），而不是服务名（如 http）。 l: 只显示正在 LISTEN（监听） 的端口。 p: 显示是哪个程序在占用这个端口。 | grep 80：在所有结果中过滤出包含 “80” 的行。 2. 结果解读 结果内容 含义 0.0.0.0:80 Nginx 正在监听 IPv4 的 80 端口。0.0.0.0 表示它接受来自任何 IP（本地和局域网）的访问。 [::]:80 Nginx 正在监听 IPv6 的 80 端口。 LISTEN 状态正常。表示端口是开放的，随时可以处理请求。 绕路方案：把 Nginx 换到 8080 端口 为了验证是不是 80 端口被封了，我们换个“高位端口”试试（高位端口通常不会被封）： 第一步：修改 Nginx 配置文件 sudo vim /etc/nginx/sites-available/default 第二步：将 80 改为 8080 Nginx\nlisten 80 default_server; listen [::]:80 default_server; 改成：\nlisten 8080 default_server; listen [::]:8080 default_server; 第三步：重启 Nginx sudo nginx -t # 检查有没有写错 sudo systemctl restart nginx 第四步：浏览器访问 在浏览器地址栏输入： http://202.38.75.252:8080\nssh连接 ssh -i .\\vlab-vm12825.pem -L 8888:localhost:8080 ubuntu@vlab.ustc.edu.cn 建立远程连接 网站权限:把项目移到标准位置 sudo cp -r /home/ubuntu/personal_file/LinuxLab/WebProg/var/www/my_site 为了自己还能修改网页,将自己加入该所有组 把你的个人账号（假设是 ubuntu）拉进 Nginx 的“工人群组”里 sudo usermod -aG www-data ubuntu sudo chown -R ubuntu:www-data /var/www/my_site (chown是更改所有组) 将 Nginx 的 root 改为 /var/www/my_site 最后，我们需要确保组员（Nginx）拥有“读”和“进入”的权限，而你拥有“写”的权限。 # 目录权限：775 (你：读写执；组：读写执；他人：读执) find /var/www/my_site -type d -exec chmod 775 {} + # 文件权限：664 (你：读写；组：读写；他人：读) find /var/www/my_site -type f -exec chmod 664 {} + 10 改变终端左侧的提示符 PS1=\u0026quot;\\u@\\h:\\w$ :\nPS1** 是 Linux 系统中一个非常重要的环境变量，它的全称是 Prompt String 1。它决定了你在终端输入命令时，左侧显示的那个**提示符（Prompt）**长什么样。\n1. 拆解这些“暗号” \\u (User)：代表当前登录的用户名 @：就是一个普通的字符“@”，用来连接用户名和主机名。 \\h (Hostname)：代表当前计算机的名字（主机名）。 :：普通的冒号分隔符。 \\w (Working directory)：代表当前所在的全路径目录（如果是家目录，会显示成 ~）。 \\$：这是一个智能符号。如果你是普通用户，它显示为 $；如果你切换成了 root（超级管理员），它会自动变成 #。 空格：最后的那个空格非常重要，它能让你的命令不紧贴着路径，看起来更清爽。 11 终端快捷键 Tab 自动补全 Tab +Tab 给出所有候选项\nCtrl+Insert 复制 Shift+Insert 粘贴\n12 Tree(展示文件结构) tree :以树状图显示文件结构 tree -L 2 :限制层数 tree -d :不显示具体文件,只看文件夹结构 tree -a :显示隐藏文件 tree -ph :显示权限 大小 tree -P \u0026ldquo;*.c|*.h\u0026rdquo; :只显示.c/.h文件 tree -I \u0026ldquo;node_modules\u0026rdquo; :排除掉特定的文件夹 tree \u0026gt; project_structure.txt :重定向输出\n13 du (Disk Usage) du:把每一个子目录的大小都列出来 du -sh . :查看整个文件夹占据空间大小 du -sh * :查看每个子文件夹大小 du -sh * | sort -hr :查看并按大小排序 du -h \u0026ndash;max-depth=1 :查看所有一级子目录\n14 df df -h :想看整个硬盘分区（比如系统盘、挂载盘）还剩多少空间\n15 feh 1. 基本打开操作 feh image.jpg # 打开单张图片 feh dir/ # 打开文件夹下所有图片（通过箭头键切换） feh -F image.jpg # 全屏打开 2. 常用“骚操作”模式 缩略图模式 (-t)： 像文件管理器一样，弹出一个窗口展示目录下所有图片的预览图。 feh -t ./personal_file/ 蒙太奇拼图模式 (-m)： 将目录下所有图片自动拼接成一张大图。 feh -m ./images/ -O montage.jpg # 拼接并保存为新图 幻灯片模式 (-D)： 每隔 2 秒自动切换下一张。 feh -D 2 ./slideshow/ 3. 必须掌握的键盘快捷键 按键 功能 方向键 / 空格 上一张 / 下一张图片 方向键 + Ctrl 缩放图片 Up / Down 放大 / 缩小 R 旋转 (90度) \u0026lt; / \u0026gt; 翻转图片 W 窗口适应图片大小 Q / Esc 退出程序 4. 进阶：用 feh 设置壁纸 feh --bg-fill /path/to/wallpaper.jpg 16 tar 把某名为source的文件或目录压缩成名为out.tar.gz的gzip格式压缩文件：tar zcvf out.tar.gz source 解压缩某名为abc.tar.gz的gzip格式压缩文件：tar zxvf abc.tar.gz 17 tmux 安装：sudo apt install tmux (Ubuntu 默认大部分已带)。 新建窗口：tmux。 离开窗口 (Detach)：按 Ctrl + B 后，再按 D。此时你的代码在后台运行！ 重新进入 (Attach)：tmux attach。 功能 命令 新建会话 tmux (或 tmux new -s myname 给会话起名) 退出并挂起 先按 Ctrl + b，然后按 d (Detach) 查看所有会话 tmux ls 重连会话 tmux a (或 tmux a -t myname) 彻底关掉会话 在 tmux 里输入 exit 或 tmux kill-session -t myname 操作逻辑：前缀键 (Prefix) tmux 的所有快捷键都需要先按一个“启动键”，默认是 Ctrl + b。 操作步骤： 按住 Ctrl 不放再按 b $\\rightarrow$ 全部松开 $\\rightarrow$ 快速按功能键。\n常用功能快捷键： 分屏（左右）：Ctrl + b $\\rightarrow$ % 分屏（上下）：Ctrl + b $\\rightarrow$ \u0026quot; 切换窗格：Ctrl + b $\\rightarrow$ 方向键 关闭当前窗格：Ctrl + b $\\rightarrow$ x 输入 tmux new -s test 进入新世界。 输入 top 看着系统资源跳动。 按 Ctrl + b 然后按 d。你会发现回到了原来的终端。 输入 tmux ls 确认 test 还在后台。 输入 tmux a -t test，你会发现 top 还在原地跳动！ 18. alias(别名) 核心逻辑 通过修改你家目录下的 .bashrc（或 .zshrc）文件，给长路径起个“外号”。 操作步骤 打开配置文件（以最常用的 bash 为例）： nano ~/.bashrc 在文件末尾添加一行： 假设你经常要去 /var/www/html/my_project/assets 这个超长目录，你可以写： alias go=\u0026#39;cd /var/www/html/my_project/assets\u0026#39; 注：go 是你自己起的命令名，你可以换成任何喜欢的词。 让配置立即生效： 保存退出后（Nano 编辑器是 Ctrl+O 回车，Ctrl+X 退出），运行： source ~/.bashrc 19. ufw 20. ai答案: 错误日志里的 (13: Permission denied) 是最直观的证据：Nginx 已经找到你的文件夹了，但是被系统拦在了门外。\n在 Linux 中，Nginx 以 www-data 用户身份运行，而你的文件夹属于 ubuntu 用户。如果中间任何一层目录（如 /home/ubuntu）没有开放“执行”权限，Nginx 就无法进入该目录寻找文件。\n终极修复方案：层层打通权限 请在虚拟机终端依次执行以下三行命令，一行都不要跳过：\nBash\n# 1. 允许其他用户（包括 Nginx）“进入”你的家目录 sudo chmod 755 /home/ubuntu # 2. 允许其他用户进入你的 personal_file 及其子目录 sudo chmod -R 755 /home/ubuntu/personal_file # 3. 确保你的网页文件本身也是可读的 sudo chmod 644 /home/ubuntu/personal_file/LinuxLab/WebProg/index.html 为什么需要执行这几步？ Linux 的权限检查是“路径式”的。即使你把 index.html 设成了 777（全开），但如果上一级的 /home/ubuntu 是私有的（通常默认是 700），Nginx 就像手里拿着钥匙却进不了院子大门的访客，依然会被报 Permission denied。\n这个太危险了,尤其是openclaw带来安全风险\n还有acl可以参考\n同步文件 实现“工业级”自动化同步，最核心的思想是：将“源码仓库”与“运行目录”分离。\n你的代码在 /home/ubuntu 目录下进行 Git 操作，而 Nginx 运行的是 /var/www/my_site 下的副本。这样既保证了安全（Nginx 进不去你的家目录），又保证了方便（你依然可以在家目录用 Git）。\n以下是两种实现方式：\n方法一：rsync 手动/脚本同步（最简单、可控） 如果你习惯在本地 git pull 后手动触发更新，rsync 是神器。它只会同步增量修改的文件，非常快。\n先创建目标目录并给好权限：\nBash\nsudo mkdir -p /var/www/my_site sudo chown -R www-data:www-data /var/www/my_site 执行同步命令：\nBash\nsudo rsync -av --delete --exclude=\u0026#39;.git\u0026#39; /home/ubuntu/personal_file/LinuxLab/my_site/ /var/www/my_site/ -av: 归档模式，保留权限和时间戳。\n--delete: 如果你在 Git 里删除了文件，/var/www 里对应的文件也会被删除。\n--exclude='.git': 不要把 .git 文件夹拷过去，Nginx 不需要它，这也能防止源码泄露。\n进阶：写成别名（Alias）： 在 ~/.bashrc 末尾加一行：alias deploy='sudo rsync -av --delete --exclude=\u0026quot;.git\u0026quot; /home/ubuntu/personal_file/LinuxLab/my_site/ /var/www/my_site/'。以后只需输入 deploy 即可一键同步。\n方法二：Git Hook 自动同步（真正的自动化） 这种方式通常用于“服务器作为远程仓库”的场景。如果你是在服务器本地 git pull，可以利用 post-merge 钩子（在合并/拉取代码后自动触发）。\n进入你家目录下的 Git 仓库钩子目录：\nBash\ncd /home/ubuntu/personal_file/LinuxLab/my_site/.git/hooks 创建 post-merge 脚本：\nBash\nnano post-merge 写入以下内容：\nBash\n#!/bin/bash # 定义目标路径 TARGET=\u0026#34;/var/www/my_site\u0026#34; SOURCE=\u0026#34;/home/ubuntu/personal_file/LinuxLab/my_site\u0026#34; echo \u0026#34;Detected git pull/merge, deploying to $TARGET...\u0026#34; # 使用 rsync 同步到 nginx 目录 sudo rsync -av --delete --exclude=\u0026#39;.git\u0026#39; \u0026#34;$SOURCE/\u0026#34; \u0026#34;$TARGET/\u0026#34; # 确保权限正确 sudo chown -R www-data:www-data \u0026#34;$TARGET\u0026#34; echo \u0026#34;Deployment complete.\u0026#34; 赋予执行权限：\nBash\nchmod +x post-merge 配置 sudo 免密（关键点）： 由于钩子是以 ubuntu 用户运行的，但同步到 /var/www 需要 sudo。为了不卡住，你需要给 rsync 加上免密： 执行 sudo visudo，在文件末尾添加：\nPlaintext\nubuntu ALL=(ALL) NOPASSWD: /usr/bin/rsync 实现效果： 以后你只要在 /home/ubuntu/.../my_site 目录下执行 git pull，代码会自动“飞”到 /var/www/my_site，Nginx 会立刻感知到更新，且没有任何权限报错。\n全局系统命令 方案一：直接创建全局系统命令（最推荐） 这种方法不依赖于任何用户的配置，直接把 deploy 变成像 ls、cd 一样的系统命令。\n创建脚本文件：\nBash\nsudo nano /usr/local/bin/deploy 把下面的内容完整复制进去：\nBash\n#!/bin/bash # 自动执行同步命令 sudo rsync -av --delete --exclude=\u0026#34;.git\u0026#34; /home/ubuntu/personal_file/LinuxLab/my_site/ /var/www/my_site/ echo \u0026#34;-----------------------------------\u0026#34; echo \u0026#34;部署成功: /home/.../my_site -\u0026gt; /var/www/my_site\u0026#34; 赋予可执行权限：\nBash\nsudo chmod +x /usr/local/bin/deploy 直接运行： 现在你在任何目录下直接输入 deploy 即可，不需要 source，也不需要加 sudo。\n","date":"2026-04-25T00:00:00Z","permalink":"/post/linux/","title":"🐧 Linux 常用命令与知识备忘"},{"content":" # 加标题 最多六级 **什么东西 ** 有加粗之效 *什么东西*有斜体之效 \u0026gt; blockquote 引用块 \u0026mdash;加标签 ————————————分割线 有序列表 远 冷 董 - 无序列表 小满 大橘 如意 `code` #include\u0026lt;stdio.h\u0026gt; int main(){ printf(“Hello, world!\\n”); return 0; } ``` 代码块 ``` 链接[title](https://www.example.com) 图片 ![alt text](image.jpg) table: |tabelhead1|tablehead2|tablehead3| |—————-|——————|——————-|\n脚注Here\u0026rsquo;s a sentence with a footnote\n1\n标题编号\nMy Great Heading 定义列表\n删除线\n~~得到的~~\n~~~ 这是啥\n任务列表\nWrite 教程第二弹 标题语法 Markdown语法 HTML # Heading level 1 \u0026lt;h1\u0026gt;Heading level 1\u0026lt;/h1\u0026gt; 最多六级标题 可以用在文本下方添加任意数量====来标识一级标题 ----来标识二级标题 段落语法 Markdown语法 HTML 用空白行将一行或多行文本分割 \u0026lt;p\u0026gt;....\u0026lt;/p\u0026gt; 注意不要缩进段落 xxxxx. 换行语法 Markdown语法 HTML 一行末尾添加两个或多个空格然后回车 \u0026lt;p\u0026gt;....\u0026lt;br\u0026gt;....\u0026lt;/p\u0026gt; 强调语法 粗体 Markdown语法 HTML **....** \u0026lt;strong\u0026gt;...\u0026lt;/strong\u0026gt; __....__ .....**...**** 斜体 Markdown语法 HTML *... \u0026lt;em\u0026gt;...\u0026lt;/em\u0026gt; _... ...*...*.... 又粗又斜 Markdown语法 HTML ***....*** \u0026lt;strong\u0026gt;\u0026lt;em\u0026gt;....\u0026lt;/em\u0026gt;\u0026lt;/strong\u0026gt; ___.....___ __*....*__ **_...._** ...***..***... 引用语法 \u0026gt;..... 或是 \u0026gt;..... \u0026gt; \u0026gt;..... Dorothy followed her through many of the beautiful rooms in her castle.\nDorothy followed her through many of the beautiful rooms in her castle.\nThe Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood.\n嵌套块引用 \u0026gt;.... \u0026gt; \u0026gt;\u0026gt;.... Dorothy followed her through many of the beautiful rooms in her castle.\nThe Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood.\n带有其它元素的块引用 \u0026gt; #### The quarterly results look great! \u0026gt; \u0026gt; - Revenue was off the chart. \u0026gt; - Profits were higher than ever. \u0026gt; \u0026gt; *Everything* is going according to **plan**. The quarterly results look great! Revenue was off the chart. Profits were higher than ever. Everything is going according to plan.\n列表语法 有序列表 Markdown语法 HTML 1. first item \u0026lt;ol\u0026gt; 2. second item \u0026lt;li\u0026gt;First item\u0026lt;/li\u0026gt; 3. third item \u0026lt;li\u0026gt;Second item\u0026lt;/li\u0026gt; \u0026lt;/ol\u0026gt; 无序列表 Markdown语法 HTML - first item \u0026lt;ul\u0026gt; - second item \u0026lt;li\u0026gt;first item\u0026lt;/li\u0026gt; - third item \u0026lt;li\u0026gt;second item\u0026lt;/li\u0026gt; \u0026lt;/ul\u0026gt; 代码块在列表中要八个空格或两个制表符 段落在代码中要缩进四个空格或一个制表符 引用快也是缩进四个空格或一个制表符 图片缩进四个空格或一个制表符 列表也是多缩进四个空格或一个制表符\n代码语法 Markdown语法 HTML `...` \u0026lt;code\u0026gt;....\u0026lt;/code\u0026gt; 遇到代码中有`的,用``...`...`...`` 代码块 四个空格或一个制表符 分割线语法 *** --- ___ 最好在分割线的前后均添加空白行 链接语法 [超链接显示名](超链接地址 \u0026quot;title名字\u0026quot;) title名字:鼠标悬停在上面会出现的文字 Markdown语法。\n网址 email地址 \u0026lt;https://markdown.com.cn\u0026gt; \u0026lt;fake@example.com\u0026gt; https://markdown.com.cn liuguangyi@mail.ustc.edu.cn\n带格式化的链接 强调链接,在链接语法前后增加星号. 将链接表示为代码 ,在方括号中添加反引号 I love supporting the **[EFF](https://eff.org)**. This is the *[Markdown Guide](https://www.markdownguide.org)*. See the section on [`code`](#code). I love supporting the EFF. This is the Markdown Guide. See the section on code.\n引用类型链接 第一部分 [hobbit-hole][1] 第一组方括号包围应显示为链接的文本 第二组括号显示了一个标签,指向存储在文档其他位置的链接 hobbit-hole\n第二部分 [label]: URL \u0026quot;可选标题\u0026quot; 放在括号中的标签,紧跟冒号和至少一个空格 URL可以选择括在尖括号中 链接的可选标题可以括在\u0026quot;\u0026quot; '' ()中 图片语法 ![tupianalt](图片链接 “图片title”) 图片也可以利用html标签来写 \u0026lt;p align=\u0026#34;center\u0026#34;\u0026gt; \u0026lt;img src=\u0026#34;./云台实物.png\u0026#34; width=\u0026#34;550\u0026#34;/\u0026gt; \u0026lt;/p\u0026gt; \u0026lt;p align=\u0026#34;center\u0026#34;\u0026gt; \u0026lt;em\u0026gt;图 1: 云台机械图纸\u0026lt;/em\u0026gt; \u0026lt;/p\u0026gt; This is the footnote;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2026-04-25T00:00:00Z","permalink":"/post/obsidian/","title":"📝 Obsidian 使用技巧与插件分享"},{"content":" 基础移动与跳转 ( / )：移动到句首 / 句尾。 { / }：移动到段首 / 段尾。 -：移动到上一行行首。 + 或 Enter：移动到下一行行首。 0：移动到绝对行首。 ^：移动到行内第一个非空字符，也就是常说的软行首。 $：移动到行尾。 |：移动到当前行第 n 列；未配合数字时可近似理解为移动到行首位置。 gg：跳到文首。 G：跳到文尾。 nG、ngg 或 :n：跳到第 n 行，例如 35G。 w / W：向后移动一个单词；W 会忽略标点。 b / B：向前移动一个单词；B 会忽略标点。 e / E：移动到单词末尾。 %：在成对符号之间跳转，如 () [] {}。 f / F + 字符：在当前行内向前 / 向后查找并跳到该字符。 t / T + 字符：在当前行内向前 / 向后查找，并停在目标字符的前一个位置。 ; / ,：重复 / 反向重复上一次 f/F/t/T 跳转。 插入与基础编辑 i：在光标前进入插入模式。 I：在行首进入插入模式。 a：在光标后进入插入模式。 A：在行尾进入插入模式。 o：在下方新开一行并进入插入模式。 O：在上方新开一行并进入插入模式。 x：删除光标后的一个字符，相当于 Delete。 X：删除光标前的一个字符，相当于 Backspace。 r：替换当前字符。 R：进入替换模式。 u：撤销。 Ctrl + R：重做。 J：合并当前行与下一行。 ~：切换当前字符的大小写。 \u0026amp;：重复执行上一次替换命令。 Ctrl + A：将光标下的数字加 1。 Ctrl + X：将光标下的数字减 1。 删除、修改与替换 dw：删除到下一个单词开头。 de：删除到当前单词末尾。 dd：删除整行。 d$：从当前光标删除到行尾。 d^：从当前光标删除到软行首。 cc：修改整行，删除后直接进入插入模式。 ce：修改到当前词尾。 C：从当前光标修改到行尾。 S：重写当前整行，作用同 cc。 s：替换当前字符并进入插入模式。 ci{：修改当前大括号 {} 内的内容。 dt + 字符：删除直到目标字符前。 ct + 字符：修改直到目标字符前。 :[范围]s/旧/新/[标志]：执行替换命令。 常用范围：\n.：当前行。 1：文首。 $：文尾。 %：全文。 a,b：指定行范围，例如 1,10。 .+5：当前行往后 5 行。 常用标志：\ng：行内全局替换。 c：逐个确认替换。 补充：\n使用 \\\u0026lt;旧\\\u0026gt; 可以匹配完整单词。 复制、粘贴与缩进 yy：复制当前整行。 Y：默认情况下等同于 yy，也是复制整行。 3yy：复制从当前行开始的 3 行。 yw：复制当前单词。 y$：从光标复制到行尾。 y^：从当前光标复制到软行首。 0y$：从绝对行首复制到行尾，不包含额外换行语义的“整行文字”复制场景很常用。 ^y$：从第一个非空字符复制到行尾。 p：粘贴到光标后或下一行。 P：粘贴到光标前或上一行。 \u0026gt;\u0026gt;：整行向右缩进。 \u0026lt;\u0026lt;：整行向左缩进。 :%y：复制全文。 :%d：删除全文。 ggvG 或 Gvgg：全选全文。 :%y+：复制全文到系统剪贴板。 \u0026quot;+p：从系统剪贴板粘贴。 查找、滚动与定位 /：向下查找关键字。 ?：向上查找关键字。 * / #：向下 / 向上查找当前光标所在单词。 H：跳到当前屏幕顶部。 M：跳到当前屏幕中间。 L：跳到当前屏幕底部。 zz：将当前行置于屏幕中央。 zt：将当前行置于屏幕顶部。 zb：将当前行置于屏幕底部。 Ctrl + F：向下翻一页。 Ctrl + B：向上翻一页。 Ctrl + D：向下翻半页。 Ctrl + U：向上翻半页。 Ctrl + E：屏幕向下滚动一行。 Ctrl + Y：屏幕向上滚动一行。 Ctrl + G：显示当前文件状态信息。 文本对象与结构化操作 yi(：复制括号 () 内部内容。 ya(：复制包含括号在内的内容。 yi\u0026quot;：复制双引号 \u0026quot;\u0026quot; 内的内容。 yit：复制 HTML / XML 标签内部内容。 yiw：复制当前小单词。 yiW：复制当前大单词。 v%：选中匹配符号之间的内容。 d%：删除匹配符号之间的内容。 y%：复制匹配符号之间的内容。 格式化、代码块与可视模式 =：执行自动缩进 / 格式化操作。 ==：格式化当前行。 =G：从当前行格式化到文件末尾。 gg=G：格式化全文。 =i{：格式化当前大括号块内部内容。 gv：重新选中上一次的可视区域。 gn：选中下一个搜索匹配项。 寄存器、标记与跳转历史 寄存器常用项：\n\u0026quot;：无名寄存器，默认复制、删除、粘贴都走这里。 0：最近一次 yank 的内容。 1-9：最近 9 次删除历史。 +：系统剪贴板寄存器。 .：上一次插入模式输入的内容，只读。 %：当前文件名，只读。 #：上一个编辑过的文件名。 :reg：查看所有寄存器。 标记与跳转：\nma：在当前位置打上名为 a 的标记。 'a：跳到标记 a 所在行的行首。 `a：跳到标记 a 的精确位置。 ``：跳回上一次光标停留的位置。 `.：跳回上一次修改的位置。 `^：跳回上一次退出插入模式的位置。 :marks：查看所有标记。 :delmarks a：删除标记 a。 :delmarks!：删除全部标记。 Ctrl + O / Ctrl + I：在跳转历史中后退 / 前进。 缓冲区、标签页与窗口管理 缓冲区与标签页：\n:ls：列出当前所有缓冲区。 :b 编号：切换到指定缓冲区。 gt / gT：切换到下一个 / 上一个标签页。 n gt：跳到第 n 个标签页。 :bn / :bp：切换到下一个 / 上一个缓冲区。 :#：显示当前行号。 窗口与分屏：\nCtrl + W + h/j/k/l 或 Ctrl + W + w：在窗口之间切换。 Ctrl + W + s：水平分屏。 Ctrl + W + v：垂直分屏。 Ctrl + W + q：关闭当前窗口。 Ctrl + W + o：只保留当前窗口，关闭其他窗口。 Ctrl + W + + / -：增大 / 减小当前窗口高度。 Ctrl + W + \u0026gt; / \u0026lt;：增大 / 减小当前窗口宽度。 Ctrl + W + =：让所有窗口等宽等高。 Ctrl + W + _：将当前窗口高度最大化。 Ctrl + W + |：将当前窗口宽度最大化。 Ctrl + W + H/J/K/L：移动当前窗口本身的位置，注意这里是大写。 Ctrl + W + r：轮换窗口位置。 插入模式专用快捷键 Ctrl + H：退格，删除前一个字符。 Ctrl + W：删除前一个单词。 Ctrl + U：删除当前行中光标前的所有内容。 Ctrl + N：补全下一个候选项。 Ctrl + P：补全上一个候选项。 Ctrl + T：增加当前行缩进。 Ctrl + D：减少当前行缩进。 Ctrl + O：临时回到普通模式执行一个命令，执行后立即回到插入模式。 命令行模式快捷键 :：进入命令行模式。 Ctrl + F：打开命令历史窗口，可像编辑文本一样编辑历史命令。 Ctrl + W：删除前一个单词。 Ctrl + R + 寄存器名：把寄存器内容插入到命令行。 Ctrl + R Ctrl + W：把当前光标下的单词直接插入到命令行。 保存与退出 :w：保存。 :wq：保存并退出。 ZZ：保存并退出。 :q!：强制退出，不保存。 ZQ：强制退出，不保存。 ","date":"2026-04-25T00:00:00Z","permalink":"/post/vim-shortcuts/","title":"🚀 Vim 编辑器快捷键极速指南"},{"content":" 光标与选择 Ctrl + L：选中当前整行；在终端中可用于清屏。 Ctrl + D：选中当前光标下的单词，再次按下可继续选中下一个相同单词。 Ctrl + Shift + L：一次性选中所有与当前选中内容相同的词。 Ctrl + Alt + ↑ / ↓：在当前光标上方或下方添加光标，进行多光标编辑。 行操作与基础编辑 Alt + ↑ / ↓：将当前行或选中的代码块向上或向下移动。 Alt + Shift + ↑ / ↓：向上或向下复制当前行或选中的代码块。 Ctrl + Enter：在下方新起一行插入。 Ctrl + Shift + Enter：在上方新起一行插入。 Ctrl + Shift + K：删除当前整行。 Ctrl + /：对当前行或选中内容进行注释/取消注释。 Alt + Shift + A：添加或取消块注释（如 /* ... */）。 Ctrl + K, Ctrl + X：清除行尾空格。 Shift + Alt + F：格式化当前文件。 导航、搜索与代码查看 Ctrl + G：跳转到指定行号。 Ctrl + P：快速搜索并跳转到文件。 Ctrl + F：在当前文件中查找。 Ctrl + H：在当前文件中替换。 F12：跳转到定义。 Alt + F12：预览定义，不离开当前位置。 Ctrl + K, Ctrl + I：显示悬浮提示。 Ctrl + Space：强制触发代码补全提示。 Ctrl + .：打开快速修复建议。 Ctrl + K, V：在侧边栏预览 Markdown。 Ctrl + K, D：在资源管理器中定位当前文件。 重构与代码折叠 F2：重命名变量、函数等符号，并同步更新引用。 Ctrl + K, Ctrl + 0：折叠全部代码块。 Ctrl + K, Ctrl + J：展开全部代码块。 Ctrl + K, Ctrl + [：递归折叠当前区域。 Ctrl + K, Ctrl + ]：递归展开当前区域。 Ctrl + K, Ctrl + 2：折叠所有二级区块；同理可使用 Ctrl + K, Ctrl + 1 到 Ctrl + K, Ctrl + 7 折叠对应级别。 编辑器与窗口管理 Ctrl + K, Enter：固定当前编辑器标签页。 Ctrl + K, Ctrl + ← / →：将当前编辑器移动到左侧或右侧分屏。 Ctrl + \\：分屏。 Alt + 数字键：在不同的编辑器标签页之间快速切换。 Ctrl + Alt + ← / →：在不同的编辑器分组之间快速切换。 Ctrl + W：关闭当前编辑器标签页或窗口。 Ctrl + K, W：关闭所有已保存的文件。 Ctrl + J：显示或隐藏底部面板。 Ctrl + K, Z：进入禅模式。 工作区与侧边栏面板 Ctrl + Shift + E：聚焦到资源管理器。 Ctrl + B：显示或隐藏侧边栏。 Ctrl + Shift + F：打开全局搜索。 Ctrl + Shift + G：打开源代码管理 / Git 面板。 Ctrl + Shift + D：打开调试面板。 Ctrl + Shift + X：打开扩展面板。 设置、语言与文件操作 Ctrl + K, Ctrl + S：打开快捷键设置。 Ctrl + K, S：全部保存。 Ctrl + K, M：更改当前文件的语言模式。 ","date":"2026-04-25T00:00:00Z","permalink":"/post/vscode-shortcuts/","title":"🛠️ VSCode 高效开发快捷键速查"}]