Appearance
tmux 会话管理
在远程服务器上执行长时间任务时,SSH 连接随时可能意外断开——网络波动、笔记本合盖休眠、WiFi 切换、VPN 超时。普通 shell 里的前台进程在 SSH 断开后会收到 SIGHUP 信号,往往直接被终止。tmux 把会话留在服务器上,SSH 断了、任务还在跑,重连后可以恢复现场。
一、tmux 的位置在哪
SSH 是客户端到服务器的一条加密通道。这条通道断了,里面的 shell 也就没了。tmux 在服务器上启动一个独立的会话进程,SSH 只是"借来看一眼"——断开不伤害 tmux,tmux 里的程序照跑。
text
本地终端 -> SSH -> 服务器 -> tmux session -> shell / 命令 / 程序也就是说,tmux 跑在 SSH 连接之外。ssh 只是远程操控 tmux 的工具,连接断了,tmux 还在。
tmux 里几个基础概念:
| 概念 | 是什么 | 可以类比 |
|---|---|---|
| session | 一个独立的 tmux 工作区 | 一个项目或一次变更操作 |
| window | session 里的标签页 | 浏览器的一个标签页,每个里面跑着不同的终端 |
| pane | window 里的分屏 | 一个窗口里切成上下或左右两块,可以同时看两样东西 |
| prefix | tmux 的快捷键前缀 | 默认是 Ctrl+b,告诉 tmux "下一个按键是给我的指令" |
tmux 对运维人员来说,最核心的功能不是分屏——是会话持久化。生产机器上跑升级、迁移、批量脚本之类的事情,在 tmux 里面执行,至少不用怕断网。
二、安装和启动
bash
# RHEL / CentOS / Rocky
yum install tmux -y
# Debian / Ubuntu
apt install tmux -y查看版本确认装上了:
bash
tmux -V创建一个命名会话:
bash
tmux new -s ops-s 给会话起个名字。tmux 默认会分配数字编号(0、1、2),多个会话同时存在的时候,数字根本判断不了哪个是生产变更、哪个是临时排查。起名字是个很小的习惯,但出了事要恢复会话时,"prod-change"比"2"好用得多。
列出所有会话:
bash
tmux ls连接到已有会话:
bash
tmux attach -t ops从会话里暂时退出(detach),回普通 shell:
text
Ctrl+b 再按 ddetach 之后 tmux 里面的程序继续跑,不会被关掉。这和按 Ctrl+d 或输入 exit 不一样——那些是真退出 shell,tmux 窗口会被关闭。
三、session 管理
session 是工作区。开始一项变更时新建一个 session,做完后关掉。
| 操作 | 命令 |
|---|---|
| 新建会话 | tmux new -s ops |
| 查看所有会话 | tmux ls |
| 进入已有会话 | tmux attach -t ops |
| 重命名会话 | tmux rename-session -t ops deploy |
| 删除会话 | tmux kill-session -t deploy |
在 tmux 里用快捷键操作 session:
| 快捷键 | 作用 |
|---|---|
Ctrl+b d | detach——暂时离开,保留会话里的一切 |
Ctrl+b $ | 重命名当前 session |
Ctrl+b s | 列出所有 session,用方向键选一个切换进去 |
一段典型的用法:
bash
tmux new -s prod-change
# 执行变更命令
./deploy.sh
# 下班了,关笔记本回家
# 先 detach:Ctrl+b 再按 d家里 ssh 回服务器:
bash
tmux attach -t prod-change
# 看到的是 deploy.sh 的完整输出,包括你离开后跑出来的部分如果 tmux attach 时报这个:
text
sessions should be nested with care, unset $TMUX to force意思是当前 shell 已经在另一个 tmux 会话里了。tmux 套 tmux 可以跑,但是快捷键会绕(外层的 Ctrl+b 被外层 tmux 吃掉,里层接收不到)。检查下当前是不是在 tmux 里:
bash
echo "$TMUX" # 有值说明当前已经在 tmux 里确认是不是已经在 tmux 里很重要,否则会误敲很多命令到错的位置。
四、window 管理
window 是 session 里面的标签页。一个 session 可以放多个 window,每个做不同的事:
| window | 用途 |
|---|---|
0: shell | 执行命令 |
1: log | 看日志 |
2: db | 数据库连接 |
3: deploy | 部署脚本 |
快捷键:
| 快捷键 | 作用 |
|---|---|
Ctrl+b c | 新建一个 window |
Ctrl+b , | 重命名当前 window |
Ctrl+b n | 切到下一个 window |
Ctrl+b p | 切到上一个 window |
Ctrl+b 0 到 9 | 直接跳到指定编号的 window |
Ctrl+b & | 关闭当前 window(会确认一次) |
命令行创建 window 也可以:
bash
tmux new-window -n log
tmux new-window -n deploy-n 指定窗口名字。排查问题时把窗口名改成 log、tcpdump、app-status 这种短名,比默认的 bash 直观很多。
五、pane 分屏
pane 是在同一个 window 里把屏幕切成几块。同时看日志和执行命令的时候很好用。
| 快捷键 | 作用 |
|---|---|
Ctrl+b % | 左右分屏(竖线切) |
Ctrl+b " | 上下分屏(横线切) |
Ctrl+b 方向键 | 在分屏之间移动光标 |
Ctrl+b x | 关闭当前所在的 pane |
Ctrl+b z | 当前 pane 最大化/还原 |
Ctrl+b 空格 | 循环切换预设布局(水平、垂直、平铺) |
命令行分屏:
bash
tmux split-window -h # 左右分屏
tmux split-window -v # 上下分屏一个常见的排查场景,上面看日志、下面敲请求:
bash
# 上面一个 pane:持续看日志
journalctl -u nginx -f
# 下面一个 pane:反复请求接口
watch -n 2 'curl -fsS http://127.0.0.1/healthz || echo failed'watch -n 2 每隔 2 秒循环执行一次命令。curl -fsS 是做健康检查常用的参数:-f 让 HTTP 错误(4xx/5xx)返回非 0 退出码;-s 静默不输出进度条;-S 搭配 -s 时让错误信息仍然显示。
分屏超过 4 个之后可读性明显下降——字太小、线太多、找焦点也慢。这时候多开个 window 比继续切分更合理。
六、复制模式和滚动
tmux 里面鼠标滚轮不一定会滚终端的输出历史。翻看之前的输出用"复制模式"。
进入复制模式:
text
Ctrl+b [进去后可以用键盘上下翻、PageUp/PageDown 翻页、/ 搜索。看完按 q 退出。
开启鼠标支持后,鼠标滚轮可以直接翻历史,拖拽可以选 pane 边界:
bash
tmux set -g mouse on这句话只对当前 tmux server 生效。想每次打开 tmux 都自动开启,写到 ~/.tmux.conf:
tmux
set -g mouse on
set -g history-limit 50000history-limit 是每个 pane 能保存的历史行数,默认是 2000 行。看大量日志的时候 2000 行根本不够,可以适当调大。受限于 tmux server 的内存,几十万行还 ok,但每个 pane 都极度调大时要看在内存上的开销。
配置写完后加载:
bash
tmux source-file ~/.tmux.conf七、长任务放在 tmux 里
适合放进 tmux 的任务:
| 场景 | 原因 |
|---|---|
| 数据迁移 | 时间长,不能因为 SSH 断开就退出 |
| 应用发布 | 需要边执行边看日志、边调整 |
| 批量巡检 | 多轮命令,结果保留在 pane 里回头翻 |
| 抓包 | tcpdump 可能跑很久,中途断开不能丢 |
| 数据库备份 | 任务长,失败后要看现场输出定位原因 |
放到 tmux 里执行的备份例子:
bash
tmux new -s backup
mkdir -p /backup/mysql
mysqldump \
--single-transaction \
--routines \
--triggers \
app_db \
> /backup/mysql/app_db-$(date +%F).sql--single-transaction 在整个备份过程中保持同一个事务视图,适合 InnoDB,能减少锁表影响。--routines 和 --triggers 带上存储过程和触发器,不然恢复时这些对象就没了。
长任务的输出保留很重要。只靠 tmux 滚动缓冲区不够稳——缓冲区被新输出冲掉也正常,而且你连回来之前跑了什么也看不到。用 tee 同时显示和存档:
bash
./deploy.sh 2>&1 | tee deploy-$(date +%F-%H%M%S).log2>&1 把 stderr 合并到 stdout 后才进管道,tee 把流分成两份——一份继续打到终端,一份写入文件。这样即使 tmux 的滚动历史已经覆盖了,日志文件里还能找到完整输出。
八、断线恢复
SSH 意外断开,重新登录服务器后:
bash
tmux ls # 看有哪些会话
tmux attach -t ops # 恢复如果 attach 时报错说会话已被另一个客户端占用——可能是之前的连接还没被超时踢掉:
bash
tmux attach -d -t ops-d 把那个客户端 detach 掉,然后自己接管。通常是自己断线的残留连接,但多人共用同一个系统用户(比如都登 root)时,-d 会把别人正在操作的界面清掉。这个场景下用 tmux list-clients -t ops 先看一眼有谁连着。
会话名忘了用 tmux ls 列出所有的:
text
ops: 3 windows (created Thu May 21 10:00:00 2026) [120x35]输出里 ops 是会话名,3 windows 表示这 session 里有 3 个窗口,120x35 是创建时的终端尺寸。
如果 tmux ls 返回这个:
text
no server running on /tmp/tmux-1000/default意思是当前用户名下没有任何活着的 tmux 会话。需要留意操作者的身份:root 创建的 tmux,普通用户是看不到的;普通用户创建的 tmux,切到 root 后也访问不到,因为 tmux server 的 socket 文件位于各用户的临时目录下。
九、screen:老环境里的备选
有些老系统上没装 tmux,但预装了 screen。screen 也能实现会话持久化。
bash
# 安装
yum install screen -y
apt install screen -y
# 创建会话
screen -S ops
# detach(离开但保留)
Ctrl+a 再按 d
# 查看会话
screen -ls
# 恢复会话
screen -r opsscreen 的 prefix 是 Ctrl+a 而不是 Ctrl+b,其他概念差不多。screen 能解决问题,但 window/pane 管理、配置体验、社区生态这几个方面,tmux 都更完善。新环境能用 tmux 就直接用 tmux。
十、一份简单的 ~/.tmux.conf
服务器上的 tmux 配置越精简越好——它是救场工具,不是日常开发环境:
tmux
# 开启鼠标支持:滚轮翻历史、点击切 pane
set -g mouse on
# 滚动缓冲区行数,排查日志时够翻一阵
set -g history-limit 50000
# window 编号从 1 开始
set -g base-index 1
setw -g pane-base-index 1
# 状态栏刷新间隔
set -g status-interval 5base-index 1 让窗口从 1 开始编号,和键盘数字行对齐。pane-base-index 1 同理,pane 编号也从 1 开始。
服务器上 tmux 不适合堆插件和复杂配置。插件依赖 tmux 版本、依赖网络安装、依赖本地文件系统——在陌生机器和应急场景下这些不确定因素都可能失效。朴素配置在任何一台服务器上都能直接工作。
十一、速查
| 操作 | 命令或快捷键 |
|---|---|
| 新建会话 | tmux new -s ops |
| 查看会话 | tmux ls |
| 恢复会话 | tmux attach -t ops |
| 强制接管 | tmux attach -d -t ops |
| 离开但保留 | Ctrl+b d |
| 新建 window | Ctrl+b c |
| 重命名 window | Ctrl+b , |
| 左右分屏 | Ctrl+b % |
| 上下分屏 | Ctrl+b " |
| 关闭 pane | Ctrl+b x |
| 最大化/还原 pane | Ctrl+b z |
| 进复制模式 | Ctrl+b [ |
| 关闭会话 | tmux kill-session -t ops |