Skip to content

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 工作区一个项目或一次变更操作
windowsession 里的标签页浏览器的一个标签页,每个跑不同的终端
panewindow 里的分屏一个窗口切成上下或左右两块,同时看两样东西
prefixtmux 的快捷键前缀默认 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  再按 d

detach 之后 tmux 里面的程序继续跑,不会被关掉。这和按 Ctrl+d 或输入 exit 不一样——那些是真退出 shell,tmux 窗口会被关闭。新手最容易搞混的就是 detach 和 exit。

三、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 时报 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,每个做不同的事——比如 0 号窗跑命令、1 号窗看日志、2 号窗连数据库、3 号窗跑部署脚本,按场景分窗,排查时切来切去比开一堆终端清爽。

window 快捷键:Ctrl+b c 新建 window、Ctrl+b , 重命名当前 window、Ctrl+b n 切到下一个、Ctrl+b p 切到上一个、Ctrl+b 09 直接跳到指定编号、Ctrl+b & 关闭当前 window(会确认一次)。

命令行创建 window 也可以:

bash
tmux new-window -n log
tmux new-window -n deploy

-n 指定窗口名字。排查问题时把窗口名改成 logtcpdumpapp-status 这种短名,比默认的 bash 直观很多——一眼就知道每个窗口在干嘛。

五、pane 分屏

pane 是在同一个 window 里把屏幕切成几块,同时看日志和执行命令的时候很好用。

pane 快捷键: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 50000

history-limit 是每个 pane 能保存的历史行数,默认只有 2000 行。看大量日志的时候 2000 行根本不够,可以适当调大。受限于 tmux server 的内存,几十万行还 ok,但每个 pane 都极度调大时要看内存开销。

配置写完后加载:

bash
tmux source-file ~/.tmux.conf

七、长任务执行

适合放进 tmux 的任务有几个共同特征:时间长、需要边执行边看输出、失败后要看现场。数据迁移(时间长,不能因为 SSH 断开就退出)、应用发布(需要边执行边看日志边调整)、批量巡检(多轮命令,结果保留在 pane 里回头翻)、抓包(tcpdump 可能跑很久,中途断开不能丢)、数据库备份(任务长,失败后要看现场输出定位原因)——这些都应该在 tmux 里跑。

放到 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).log

2>&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 返回 no server running on /tmp/tmux-1000/default,意思是当前用户名下没有任何活着的 tmux 会话。需要留意操作者的身份:root 创建的 tmux,普通用户是看不到的;普通用户创建的 tmux,切到 root 后也访问不到——因为 tmux server 的 socket 文件位于各用户的临时目录下。"明明我创建了会话怎么 attach 不上",十有八九是身份不对。

九、screen 备选

有些老系统上没装 tmux,但预装了 screen。screen 也能实现会话持久化:

bash
# 安装
yum install screen -y
apt install screen -y

# 创建会话
screen -S ops

# detach(离开但保留)
Ctrl+a  再按 d

# 查看会话
screen -ls

# 恢复会话
screen -r ops

screen 的 prefix 是 Ctrl+a 而不是 Ctrl+b,其他概念差不多。screen 能解决问题,但 window/pane 管理、配置体验、社区生态这几个方面,tmux 都更完善。新环境能用 tmux 就直接用 tmux,screen 当作老机器上的备选就行。

十、tmux 配置

服务器上的 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 5

base-index 1 让窗口从 1 开始编号,和键盘数字行对齐(数字键 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
新建 windowCtrl+b c
重命名 windowCtrl+b ,
左右分屏Ctrl+b %
上下分屏Ctrl+b "
关闭 paneCtrl+b x
最大化/还原 paneCtrl+b z
进复制模式Ctrl+b [
关闭会话tmux kill-session -t ops