远程连服务器跑任务,最怕两件事:SSH 一断,正在跑的训练、编译、迁移全没了;或者开了一堆终端窗口,切来切去找不到哪个在干啥。很多人用 nohup ... & 或者 disown 勉强应付,但看不到实时输出、管理起来也乱。tmux 解决的正好是这个问题:它把”终端会话”从”网络连接”里解耦出来——会话在服务器上独立存活,你断网、关电脑都不影响它,回来再”贴”回去接着看。本文讲清从入门到一键拉起开发环境的完整用法。
核心概念:session、window、pane
tmux 的层级很好记:session(会话)是一个独立的工作空间,断网后它还在;一个 session 里可以开多个 window(窗口),像浏览器标签页;每个 window 又能切成多个 pane(窗格),左右上下并排。理解这三层,就理解了 tmux 的全部组织方式。常见用法是:一个项目一个 session,里面按”前端/后端/日志”分窗格。
基础操作:新建、脱离、重连
三个动作覆盖 80% 场景——新建、脱离(detach)、重连(attach):
# 新建命名会话并进入
tmux new -s dev
# 脱离当前会话(进程继续在后台跑)
# 快捷键:前缀键(默认 Ctrl+b) 然后按 d
# 等效命令:
tmux detach-client
# 重连断开的会话
tmux attach -t dev
# 列出所有会话,看看哪个还在
tmux ls
记住:脱离不是退出,会话里的进程一个都没停。这和直接关掉终端有本质区别——关终端等于给进程发 SIGHUP,tmux 的会话则帮进程挡下了这个信号。配合GitHub Actions或跳转机做长任务时,它尤其省心。
改配置:让前缀键和鼠标更好用
默认前缀键 Ctrl+b 有点别扭,且不开鼠标时滚动、选窗格都不方便。把下面这段写进 ~/.tmux.conf 立刻顺手:
# 改前缀为 Ctrl+a(更顺手,且不和 Bash 快捷键撞)
set -g prefix C-a
unbind C-b
bind C-a send-prefix
# 开启鼠标:可直接点窗格、滚轮滚动历史
set -g mouse on
# 状态栏与分隔线美化
set -g status-style bg=default
set -g pane-border-style fg=cyan
set -g pane-active-border-style fg=white
# 重连后编号从 1 开始(默认从 0)
set -g base-index 1
setw -g pane-base-index 1
改完用 tmux source-file ~/.tmux.conf 重新加载即可,不用重启会话。鼠标开启后,滚轮能翻历史输出,这在排查长日志时比反复 cat 方便太多。
窗格:一个屏幕干多件事
并排看”运行 + 日志”是 tmux 最爽的用法。分割与切换都走前缀键:
# 左右分屏
# 前缀键 然后按 %
tmux split-window -h
# 上下分屏
# 前缀键 然后按 "
tmux split-window -v
# 在窗格间切换(方向键)
# 前缀键 然后按 方向键
# 当前窗格全屏/还原(前缀键 z)
# 关闭当前窗格:exit 或 前缀键 x
一个常用的实战布局是:左半屏跑主进程(前端 dev server 或训练脚本),右半屏上下切成”日志 + 监控”两块——上面 tail -f 看应用日志,下面挂一个 htop 或 watch df -h 盯资源。这样一屏就能同时掌握”程序在干什么、报了什么错、机器还撑不撑得住”,比在多个 SSH 窗口间来回切省心得多。需要全屏看某块时,前缀键 z 临时放大,看完再按一次还原。
脚本化:一键拉起开发环境
每次手动开会话、切窗格、敲命令太烦。把环境固化成脚本,ssh 上去一条命令就恢复工作状态:
#!/usr/bin/env bash
# 开发会话不存在则创建并铺好窗格
tmux has-session -t dev 2>/dev/null || {
tmux new -d -s dev
tmux send-keys -t dev 'cd ~/project && npm run dev' C-m
tmux split-window -h -t dev
tmux send-keys -t dev 'docker compose up' C-m
tmux split-window -v -t dev
tmux send-keys -t dev 'tail -f /var/log/app.log' C-m
}
tmux attach -t dev
这段脚本先判断 dev 会话是否存在,不存在才建,并自动铺好”前端 / 容器 / 日志”三个窗格、各自跑好命令。它和Terraform 造环境、Docker 网络是同一思路:把”怎么起一套工作环境”变成可复现的代码,而不是记在脑子里。在K8s集群里排障时,我也会在跳板机上开一个 tmux 会话挂着 kubectl logs -f,断线再连依旧在。
常用快捷键速查
| 操作 | 快捷键(前缀键 + 键) | 等效命令 |
|---|---|---|
| 脱离会话 | 前缀键 d | tmux detach-client |
| 左右分屏 | 前缀键 % | split-window -h |
| 上下分屏 | 前缀键 “ | split-window -v |
| 切换窗格 | 前缀键 方向键 | select-pane |
| 新建窗口 | 前缀键 c | new-window |
| 重命名会话 | 前缀键 $ | rename-session |
三个常见坑
- 前缀键冲突:在嵌套 tmux(本地套远程)里,按一次前缀键只传给外层;想操作内层要连按两次前缀键。
- 复制模式:开鼠标后默认滚轮滚历史,但想复制文本要用”前缀键 [ “进入复制模式,而非直接用终端选中——两者选中的范围不同。
- 环境变量不继承:会话创建时定下了环境变量,之后改了
.bashrc不会自动进已有会话;新开会话才生效。
为什么不直接用 nohup 或 screen
很多人会问:nohup ... & 也能后台跑,为什么还要 tmux?关键差在三处:一是可见性,nohup 把输出丢进 nohup.out,想看实时日志还得 tail -f,tmux 的窗格里输出是活的;二是管理粒度,nohup 任务一旦多了就只能靠 ps 翻 PID 找,tmux 用命名会话一眼分清”哪个是 dev、哪个是训练”;三是复用,tmux 会话能随时 detach/attach,nohup 进程一旦脱离终端就再也回不到一个统一界面。至于 screen,它和 tmux 思路类似,但 tmux 的窗格分割、脚本化、状态栏可定制都更强,社区也早已默认 tmux 为首选。换句话说:临时一次性后台任务用 nohup 无妨,需要”看着、管着、随时回来接着看”的长任务,tmux 才是正解。
落地到生产,我的一条经验是:任何”跑起来就别动它”的服务,先开 tmux 再启动,再把 attach 脚本写进跳板机的欢迎语或 alias。这样队友接手时一条 tmux attach -t dev 就能接管全部上下文,而不是在群里问”那个进程谁起的、日志在哪”。配合VS Code 远程开发插件,本地编辑器连上服务器后,真正需要的就是这一层不会断的会话——断网、换电脑、VPC 切换都不影响远端进度。
小结
tmux 的本质,是把”终端会话”从”网络连接”里解放出来:断网不丢进度、一个会话管多窗格、环境可脚本化复现。它和服务器安全加固里”让运维可观测、可恢复”的理念一致——你的长时间任务,不该因为一次网络抖动就从头再来。从今天起,远程跑长任务先 tmux new -s,告别 nohup 和反复 SSH,把工作环境固化成那一条 attach 脚本,效率立刻上一个台阶。




