一、tmux — 终端复用器
它解决什么问题
SSH 连接到远程服务器时,一旦网络断开或关闭终端窗口,正在运行的程序(比如 hugo server、apt install)会被强制终止。
tmux 在用户和服务器之间插入了一个持久层——你关掉终端、断开 SSH,tmux 里的程序继续跑。下次连上,tmux a 一切恢复原样。
普通 SSH: SSH + tmux:
你 ──SSH── 服务器 你 ──SSH── 服务器
│ │
跑程序 tmux(持久层)
│ │
SSH 断开 → 程序死 SSH 断开 → tmux 里的程序继续跑
下次连上 → tmux a → 恢复
层级结构
tmux 服务
├── session 0(工作区 A:博客开发)
│ ├── window 0(这个窗口跑 hugo server)
│ │ ├── pane 0(左边:编辑 config.yml)
│ │ └── pane 1(右边:看日志)
│ └── window 1(这个窗口跑 docker)
│ └── pane 0
├── session 1(工作区 B:渗透练习)
│ ├── window 0(DVWA 目录)
│ └── window 1(查资料)
└── session 2
session = 独立工作区,window = 浏览器标签页,pane = 分屏。 你在一个 session 里"挂起"(detach),另一个终端可以"接入"(attach),无缝切换。
前缀键:Ctrl+A
tmux 所有快捷键都先按一次前缀键(告诉 tmux"下一个按键是给你的,不是给终端里的程序的"),再按功能键。默认前缀是 Ctrl+B,但这里改成 Ctrl+A——离手指更近,按着更舒服。
操作节奏:按下 Ctrl+A → 松开手指 → 按下一个键。 不是同时按;是先后按。
完整操作速查
| 操作 | 快捷键 | 说明 |
|---|---|---|
| 新建 session | tmux |
创建一个 session,默认带一个 window 和一个 pane |
| 左右分屏 | Ctrl+A 然后 % |
当前 pane 左右平分 |
| 上下分屏 | Ctrl+A 然后 " |
当前 pane 上下平分 |
| 关闭 pane | Ctrl+D |
pane 全关了 → 关 window;window 全关了 → 关 session |
| 选 pane(鼠标) | 鼠标点击 | 直接定位 |
| 选 pane(键盘) | Ctrl+A 然后 方向键 |
相邻 pane 间移动 |
| 调分割线(鼠标) | 拖拽分割线 | 最直观 |
| 调分割线(键盘) | Ctrl+A + 方向键(按住不放) |
微调 |
| 全屏/取消 | Ctrl+A 然后 z |
当前 pane 临时撑满整个窗口 |
| 挂起 session | Ctrl+A 然后 d |
detach——session 在后台继续跑,你回到普通终端 |
| 恢复 session | tmux a |
attach——一切恢复 |
| 选择 session | Ctrl+A 然后 s |
方向键上下选、右展开、左收起 |
| 新建 window | Ctrl+A 然后 c |
在当前 session 里开新标签页 |
| 选择 window | Ctrl+A 然后 w |
同 session 选择方式 |
| 翻阅内容 | Ctrl+A 然后 PageUp 或 鼠标滚轮 |
查看历史输出 |
| 文本选择 | 按住 Shift + 鼠标拖拽 |
tmux 里不按 Shift 拖拽会触发 tmux 自己的选择模式 |
| 复制 | Ctrl+A 然后 [ → 鼠标选文本(自动复制) |
进入 tmux 的复制模式 |
| 粘贴 | Ctrl+A 然后 ] |
粘贴 tmux 剪贴板内容 |
二、vim — 终端里的文本编辑器
为什么学 vim
服务器上没有图形界面,没有 VS Code。改配置文件、写脚本、编辑代码——全在终端里完成。vim 是 Linux 世界最通用的终端编辑器,任何一台 Linux 都预装了 vi(vim 的前身)。
vim 不是"简陋版记事本"。它的核心哲学是:大部分时间在阅读/浏览代码,少数时间在修改。 所以默认处于"只读浏览模式"(一般命令模式),而不是"打字模式"(编辑模式)。
三种模式
┌────────── 一般命令模式 ──────────┐
│ (默认状态,按什么键触发什么动作) │
│ 浏览、复制、粘贴、删除、跳转 │
│ │
│ 按 i → 进入编辑模式 │
│ 按 : 或 / → 进入命令行模式 │
└──────────┬──────────────┬────────┘
│ │
▼ ▼
┌── 编辑模式 ──┐ ┌── 命令行模式 ──┐
│ 正常打字 │ │ 保存、退出 │
│ ESC → 退回 │ │ 查找、替换 │
└──────────────┘ │ ESC → 退回 │
└────────────────┘
移动光标
| 操作 | 按键 | 记忆技巧 |
|---|---|---|
| 左 | h |
在最左边 |
| 下 | j |
j 像往下的钩子 |
| 上 | k |
k 像往上指 |
| 右 | l |
在最右边 |
| 右移 n 个字符 | n<Space> |
|
| 行首 | 0 或 Home |
|
| 行尾 | $ 或 End |
正则里 $ 就是行尾 |
| 文件最后一行 | G |
|
| 文件第一行 | gg |
|
| 第 n 行 | nG 或 :n |
|
| 向下 n 行 | n<Enter> |
查找与替换
| 操作 | 命令 | 说明 |
|---|---|---|
| 向下找 word | /word |
n 下一个,N 上一个 |
| 向上找 word | ?word |
|
| 第 n1 到 n2 行替换 | :n1,n2s/word1/word2/g |
g = 每行全部替换 |
| 全文替换 | :1,$s/word1/word2/g |
1,$ = 第一行到最后一行 |
| 全文替换(逐个确认) | :1,$s/word1/word2/gc |
每次替换前 y/n 确认 |
| 关闭高亮 | :noh |
查找后的高亮不消失,用这个关 |
复制、剪切、粘贴、删除
vim 里的"删除"本质是"剪切"——被删的内容自动进入寄存器,可以 p 粘贴出来。
| 操作 | 按键 |
|---|---|
| 选中文本 | v + 方向键移动 |
| 复制选中 | y |
| 复制整行 | yy |
| 删除选中(剪切) | d |
| 删除整行(剪切) | dd |
| 粘贴 | p(光标下一行/下一位置) |
| 撤销 | u |
| 重做(取消撤销) | Ctrl+R |
缩进与格式化
| 操作 | 按键 |
|---|---|
| 选中后右缩进 | v 选中 → > |
| 选中后左缩进 | v 选中 → < |
| 全文自动格式化 | gg=G |
保存、退出、配置
| 操作 | 命令 |
|---|---|
| 保存 | :w |
| 强制保存 | :w! |
| 退出 | :q |
| 强制退出(不保存) | :q! |
| 保存并退出 | :wq |
| 显示行号 | :set nu |
| 隐藏行号 | :set nonu |
| 粘贴模式(不自动缩进) | :set paste |
| 取消粘贴模式 | :set nopaste |
| 卡死时强制中断 | Ctrl+Q |
.swp 文件异常处理
每次用 vim 打开文件,vim 自动创建一个 .filename.swp 的临时文件用于崩溃恢复。如果 vim 异常退出,.swp 残留,下次打开会报警。
解决方法:
1. 找到另一个正在编辑该文件的 vim 进程,退出它
2. 或者直接删掉 .swp 文件:rm .filename.swp
三、vim 作业题解
homework_0
进入 homework_0,创建 names.txt,写入姓名,每行一个:
cd homework_0
vim names.txt
按 i 进入编辑模式,输入:
AcWing
yxc
Bob
张强
李明
Alice
按 ESC,输入 :wq 保存退出
homework_1
cd homework_1
vim problem.txt
[1] 最后一行第101个字符:G(跳到最后一行)→ 100<Space>(右移100个字符,光标在第101个)
→ d(删除当前字符)
[2] 第3行第8个字符:3G(跳到第3行)→ 7<Space>(右移7个字符,光标在第8个)
→ d
[3] 第1行第30个字符:gg(跳到第1行)→ 29<Space> → d
[4] 第16行第55个字符:16G → 54<Space> → d
[5] 第9行第80个字符:9G → 79<Space> → d
:wq 保存退出
homework_2
cd homework_2
vim problem.txt
[1] 在第1个"two"后面添加"abc"
/two<Enter>(找到第1个two)→ e(光标跳到单词末尾)→ i(进入编辑模式)→ 输入abc → ESC
[2] 在第2个"two"前面添加"def"
n(跳到第2个two)→ i(进入编辑模式)→ 输入def → ESC
[3] 将第3个"two"后面的连续12个字符删掉
n(跳到第3个two)→ e(跳到单词末尾)→ l(右移一个字符,到要删除的第一个字符)
→ v → 11<Space>(选中12个字符)→ d
[4] 将第4个"two"所在的行删掉
n(跳到第4个two)→ dd
:wq 保存退出
homework_3
cd homework_3
vim problem.txt
[1] 将第5行至15行中所有of替换成OF
:5,15s/of/OF/g
[2] 将全文中所有the替换成THE
:1,$s/the/THE/g
[3] 将全文中的is奇数不变,偶数变为IS
:1,$s/is/IS/gc
(然后 n(n不替换) y(替换) 交替按,实现奇数不变偶数替换)
:wq 保存退出
homework_4
cd homework_4
vim problem.txt
[1] 删除第11行:11G(跳到第11行)→ dd
[2] 粘贴到文件末尾下一行:G(跳到最后一行)→ p
[3] 复制第5行:5G(跳到第5行)→ yy
[4] 粘贴到文件末尾下一行:G → p
:wq 保存退出
homework_5
cd homework_5
vim problem.txt
[1] 删除第11行第15个字符至第13行第5个字符:
11G → 14<Space>(光标在第11行第15个字符)
→ v(进入可视模式)→ 13G → 5<Space>(选到第13行第5个字符)
→ d(删除选中内容)
[2] 粘贴到文件末尾(不另起一行):
G → $(跳到最后一行的行尾)→ p
[3] 复制第5行第88个字符至第7行第6个字符:
5G → 87<Space>(光标在第5行第88个字符)
→ v → 7G → 6<Space>(选到第7行第6个字符)
→ y(复制选中内容)
[4] 粘贴到文件末尾(不另起一行):
G → $ → p
:wq 保存退出
homework_6
cd homework_6
[1] 清空 source0.cpp:
vim source0.cpp → gg(跳到第一行)→ dG(从当前行删到文件末尾)
→ :wq 保存退出
或者直接:> source0.cpp
[2] 将 source1.cpp 中的第1-3行和第12-24行复制到 source0.cpp:
vim source1.cpp
→ gg(跳到第一行)→ v → 3G(选到第3行末尾)→ y
→ :q 退出
vim source0.cpp
→ p(粘贴第1-3行)
→ :wq 退出
vim source1.cpp
→ 12G → v → 24G → y
→ :q 退出
vim source0.cpp
→ G(跳到最后)→ p
→ :wq 保存退出
homework_7
cd homework_7
vim source.cpp
gg=G(全文格式化)
:wq 保存退出
homework_8
cd homework_8
vim source.cpp
[1] 将第15-21行向右缩进2次:
15G → v → 21G → >(第一次缩进)
15G → v → 21G → >(第二次缩进)
或:15Gv21G> 执行两次
[2] 将第22-23行向左缩进1次:
22G → v → 23G → <
:wq 保存退出
homework_9
cd homework_9
浏览器打开链接:https://www.acwing.com/activity/content/code/content/1694465/
复制全部代码
vim source.cpp
按 i 进入编辑模式
右键粘贴(或 Ctrl+Shift+V)
ESC
:wq 保存退出
四、tmux + vim 的组合使用场景
# 1. 连上服务器
ssh mycvm
# 2. 启动 tmux(如果已有 session,用 tmux a 恢复)
tmux
# 3. 左 pane 编辑代码
Ctrl+A 然后 %
# 4. 右 pane 跑程序/看日志
Ctrl+A 然后 方向键右 → 到这个 pane → 运行命令
# 5. 编辑时:左边 vim 写代码,右边 tail -f 看日志
# 左边修改保存,右边立刻看到效果
# 6. 下班了,断开连接
Ctrl+A 然后 d(挂起)→ 关闭终端 → 回家
# 7. 到家后再连上
ssh mycvm → tmux a → 一切还是下班前那样
本文基于 ACWing Linux 基础课笔记整理,作业题解已补全。