tmux 教程:把一次 SSH 登录变成可恢复的终端工作台
终端窗口关闭、SSH 连接抖动或笔记本合盖,常常会把正在运行的构建、日志观察和远程编辑一起打断。tmux 的价值不在于把屏幕切成几块,而在于把程序运行的归属从一次 terminal client 连接中分离出来:client 可以离开,session 仍留在主机上。
tmux 是 terminal multiplexer,不是终端模拟器,也不是进程监督器。它运行在已有终端里,管理一组带 pseudo-terminal 的程序;它能抵抗 terminal 或网络连接中断,却不会让程序跨主机重启自动恢复。这个边界决定了 tmux 适合管理交互式工作台,不应被当成 systemd、容器编排器或备份系统的替代品。
先建立正确的对象关系
tmux server 管理 client、session、window 和 pane。client attach 到一个 session;session 维护 window 列表;window 由一个或多个 pane 组成;每个 pane 都承载一个 pseudo-terminal。window 还可以链接给多个 session,因此这不是一棵严格的 client 到 pane 的树。tmux(1) 手册对这组关系有正式定义。
flowchart LR
T[已有终端] --> C[tmux client]
C -->|attach| S[session: project]
S --> W1[window: editor]
S --> W2[window: logs]
W1 --> P1[pane: shell]
W1 --> P2[pane: test]
W2 --> P3[pane: tail -f]
SV[tmux server] -.管理.-> C
SV -.管理.-> S
SV -.管理.-> W1
SV -.管理.-> W2
这张图回答一个常见疑问:断线后为什么任务还在。C-b d 只是让 client detach,server、session 和 pane 没有被销毁,pane 中的程序仍继续运行。反过来,kill-pane、kill-window、kill-session 或 kill-server 会关闭对应范围的内容;主机重启也会结束这些进程。官方入门文档把 detach 描述为 client 离开外部终端、session 和程序留在后台运行,而不是持久化快照。Getting Started
五分钟建立第一个工作台
macOS 可以通过 Homebrew 安装:
1 | |
Homebrew 将 tmux 定义为 terminal multiplexer,并提供 brew install tmux 安装入口。Homebrew Formulae 在 Linux 上,使用发行版的软件包管理器安装同名包即可。
建立一个可反复进入的命名 session:
1 | |
new 是 new-session 的别名,-s project 指定 session 名,-A 表示若 project 已存在则 attach,不存在才新建。这样不需要先执行 tmux ls 再判断是否创建。官方手册 将这个行为定义为 new-session -A 按 attach-session 处理已有的目标 session。
进入 tmux 后,默认前缀是 C-b,意思是按住 Ctrl 键再按 b,松开后再按后一枚按键。最小操作集只有六个:
| 目的 | 按键 | 结果 |
|---|---|---|
| 新建 window | C-b c |
为一个独立任务新建工作页 |
| 竖向切分 pane | C-b % |
左右并排 |
| 横向切分 pane | C-b " |
上下并排 |
| 切换 pane | C-b + 方向键 或 C-b o |
改变输入目标 |
| 临时离开 | C-b d |
detach,程序继续运行 |
| 回到 session | tmux attach -t project |
重新 attach |
一个可运行的起点是:把编辑器或交互 shell 放在左侧,把测试命令放在右侧;另开一个 logs window 持续观察日志。window 用来隔离会停留较久的任务,pane 用来并排放置需要同时观察的命令。不要把每条临时命令都切成 pane;一个 window 内超过三四个 pane 后,终端宽度会先成为瓶颈。
把工作单元划在正确的边界上
session、window 和 pane 的划分没有唯一答案,但边界一旦稳定,恢复成本会明显下降。
| 工作单元 | 适合承载的东西 | 命名建议 | 何时销毁 |
|---|---|---|---|
| session | 一个仓库、线上故障、一次远程主机工作 | project、ops、incident-42 |
工作目标结束 |
| window | editor、日志、数据库控制台、构建观察 | code、logs、db、watch |
子任务结束 |
| pane | 一组需要同时比较或彼此依赖的命令 | 不必强行命名 | 观察关系结束 |
这种划分可以概括为“持久对象放高层,并发观察放低层”:session 表示工作上下文,window 表示延续较久的职责,pane 表示当前视野。一个仓库一个 session、一个角色一个 window、一个观察关系一个 pane,比按工具类型把所有任务堆进同一 session 更容易重连和清理。
让新 pane 保持当前目录
默认切分后,新 pane 的工作目录未必符合当前任务。tmux 提供 pane_current_path format;官方 Recipes 用它为默认绑定补上 -c,让新 window 和 pane 继承当前 pane 的路径。Recipes
在 ~/.tmux.conf 放入这组小配置:
1 | |
mouse on 允许鼠标选择、切换和调整;history-limit 决定每个 pane 保留的历史行数;renumber-windows on 会在 window 关闭后收拢编号。mode-keys vi 和 status-keys vi 只影响 copy mode 与命令提示符的按键表,不改变 shell 或编辑器的按键。Getting Started
配置文件会在 tmux server 启动时读取一次,而不是每建一个 session 就重新读取。修改后,在 tmux 内或普通 shell 中执行:
1 | |
这会加载大多数键绑定和选项。涉及 clipboard、TERM 或 terminal capability 的配置,官方 Clipboard 指南建议彻底重启 server 后再验证,因为外部终端能力会参与初始化。Clipboard
滚动、复制与系统剪贴板是三件事
C-b [ 进入 copy mode,可以查看 pane 的历史缓冲区;C-b ] 将 tmux 的 paste buffer 插入当前 pane。进入 copy mode 并不保证复制内容已经进入 macOS、Wayland、X11 或远程电脑的系统剪贴板。tmux(1) 手册 明确把 copy mode 的结果定义为 paste buffer。
系统剪贴板同步依赖外部 terminal 对 OSC 52 的支持、tmux 的 set-clipboard 选项,以及相关 terminfo capability。官方 Clipboard 文档还指出:set-clipboard on 允许在 pane 里输出文本的应用设置 tmux buffer 和外部剪贴板;运行不受信任命令时,这个权限要格外谨慎。Clipboard
先用两个检查确认环境,再考虑加入配置:
1 | |
远程 SSH 场景尤其不要假定本机 pbcopy、xclip 或 xsel 可以直接工作;这些工具通常只能连接其所在机器的本地剪贴板服务。OSC 52 可以跨 SSH 传递,但仍取决于 client terminal 是否允许。
远程主机上的正确用法
在远程主机登陆后,创建或进入远端 session:
1 | |
本地网络短暂中断时,远端 tmux server 仍在远端主机,ops session 里的命令继续执行。重新连接后再执行 tmux attach -t ops 即可恢复。session 归属的是运行 tmux server 的那台机器,不是本地 terminal,也不是 SSH client。
同一个 session 被多台 client 同时 attach 时,窗口尺寸和输入焦点需要额外约定。需要独占时可以使用:
1 | |
-d 会 detach 其他已连到该 session 的 client。tmux(1) 手册 对多客户端窗口尺寸给出了 largest、smallest、latest 和 manual 策略;屏幕尺寸差异很大时,应先决定是否允许共同观察,再调整 window-size,不要把布局错乱误判为 tmux 丢失数据。Advanced Use
如果已经在本地 tmux 内,又进入远端 tmux,两个实例会竞争相同的前缀。默认情况下连续按两次 C-b,外层会把一个前缀发给内层;随后按内层命令键即可。不要把 unset $TMUX 当成常规解法:它绕开的是嵌套保护,不会解决“当前按键究竟交给哪一层”的问题。tmux 的示例配置会检测 TMUX 环境变量,正是为了对嵌套环境采取不同策略。example_tmux.conf
同步输入只适合可重复且无副作用的命令
tmux 可以在同一 window 内把输入送到多个 pane:
1 | |
这适合对多台测试机发送同一条只读诊断命令,也适合在多个环境里输入相同的临时查询。synchronize-panes 会把键入内容同步给同一 window 的其他非 mode pane,官方文档明确提醒要谨慎使用。Getting Started
不要在同步输入开启时执行 rm、部署、数据库写入、迁移或包含凭据的命令。先用 hostname 或 pwd 做一次可见的无副作用验证,再输入真正的命令;完成后立即关闭同步。批量操作的问题不是 tmux 是否能发送,而是目标集合和副作用是否已经被确认。
故障排查从对象边界开始
| 现象 | 先检查什么 | 常见原因 |
|---|---|---|
tmux attach 找不到 session |
tmux ls |
session 被 kill,或连到了另一台主机 |
| 断线后任务不见了 | tmux ls、shell history、服务日志 |
任务未在 tmux 内启动,或 pane/window/session/server 已退出 |
| 新 pane 跑到错误目录 | pwd、tmux show-options -g |
未使用 pane_current_path binding |
| 复制不到系统剪贴板 | tmux info | grep 'Ms:'、terminal 设置 |
OSC 52、terminal capability 或剪贴板策略不匹配 |
| 多客户端布局出现空白或裁切 | tmux show-window-options window-size |
attached client 尺寸策略不适合当前场景 |
排查顺序保持一致:确认连接的是哪台主机,再确认 server 是否存在,然后检查 session、window 和 pane。这个顺序比从快捷键开始猜更快,因为 tmux 的大多数问题本质上是对象位置或生命周期判断错误。
速查:把工作流固化为三条命令
| 需求 | 命令或按键 | 采用的模式 |
|---|---|---|
| 进入一个稳定工作区 | tmux new -A -s project |
名称作为会话入口 |
| 暂时离开而不停止任务 | C-b d |
client 与任务生命周期分离 |
| 恢复远程工作 | tmux attach -t project |
重新 attach 同一 session |
| 新建相邻观察面 | C-b % 或 C-b " |
并排观察,不拆分任务归属 |
| 让新 pane 跟随目录 | -c "#{pane_current_path}" |
上下文继承 |
| 批量执行同一条只读命令 | 临时开启 synchronize-panes |
显式放大输入,立即关闭 |
稳定的 tmux 使用习惯不需要复杂主题或插件。命名 session、按职责建立 window、仅为并行观察切分 pane,并把 detach 当成连接动作而不是保存动作,就足以覆盖大多数本地开发和远程 SSH 场景。
参考资料
- tmux(1) 手册 — server、client、session、window、pane、copy mode 与
new-session语义。 - tmux Wiki: Getting Started — 基础交互、detach、配置与选项。
- tmux Wiki: Advanced Use — working directory、window-size 和高级配置检查。
- tmux Wiki: FAQ — 多 client 尺寸、SSH agent 与常见边界。
- tmux Wiki: Recipes — 继承当前目录的 bindings。
- tmux Wiki: Clipboard — OSC 52、
set-clipboard、外部工具和安全限制。 - tmux example configuration — 当前项目提供的配置范例。
- Homebrew Formulae: tmux — macOS 安装入口。
