1. 先搞明白tmux是干嘛的,再谈命令
1.1 三个最常见的痛点
如果你和我一样,经常需要远程登录服务器做开发、跑任务或者维护系统,下面几个场景一定不陌生。
第一,SSH连接一旦断开,正在运行的前台进程就跟着一起死掉。比如你正在跑一个需要好几个小时的训练任务,或者正在执行一个耗时的数据迁移脚本,网络抖动一下,窗口一断,任务直接中断,一切又得从头再来。第二,想在同一时间看日志、改配置、跑命令,只能在一个终端里来回切换,或者开一堆标签页,来回找窗口本身就浪费了不少精力。第三,临时需要离开一下,但又不想眼睁睁看着任务被关掉,只能想办法让进程在后台挂住,要么 nohup 要么写脚本,操作繁琐,管理起来也麻烦。
这三个痛点指向同一个需求:需要一个能把终端会话从登录终端中彻底"解耦"的工具——你在或不在,它都在后台稳稳运行。tmux(terminal multiplexer,终端复用器)就是这么诞生的。
1.2 tmux到底能做什么
tmux是一个运行在终端里的程序,核心作用就是"复用你的终端"。它允许你在同一个终端窗口中划分出多个独立的会话、窗口和窗格,并且把这些会话托管在后台。即使你的SSH断开了、终端窗口关闭了,tmux里的会话照样运行,等你重新连上主机之后,再用 tmux attach 命令把会话接回来,界面和进程状态都还保持在断开前的样子。
这套能力带来的直接收益有三个:持久性、并行性、恢复能力。持久性保证长任务不中断;并行性让你在一个屏幕里同时处理多件事;恢复能力则是断开之后能找回原来的工作现场。另外tmux还支持多人共享同一个会话,两个人连接到同一台服务器、同一个tmux会话,就能实时看到彼此的输入和输出,这在远程协助、结对排障时非常好用。
这篇内容适合所有经常和终端打交道的人,不管是运维、后端开发、数据分析还是普通服务器使用者。命令本身不难,重点是把涉及的几个核心概念捋清楚,然后配合自己常用的场景做定制,才能真正用起来顺手。
2. tmux的四个层级:服务器、会话、窗口、窗格
2.1 四层结构到底怎么理解
tmux的内部结构可以分为四层,从上到下依次是:服务器(server) → 会话(session) → 窗口(window) → 窗格(pane)。很多新手第一次接触时被这四层结构绕晕,其实用酒店来打比方就很好懂。
服务器相当于整栋酒店大楼。只要tmux还运行着,服务器就存在,它是所有会话的宿主。会话相当于你入住的一个房间,每开一个tmux会话,就是在大楼里新开了一间房,你可以在房间里干各种事情。窗口相当于房间内部的不同功能区域,一个会话里可以开多个窗口,每个窗口之间相互独立,互不干扰。窗格则相当于把某个区域再隔成几个小间,你在一个窗口里可以把屏幕横向或纵向切分,同时显示多个内容。
正常人平时在一台服务器上最多开一个tmux服务器就够了。在这个服务器里面,你可以挂很多个会话,比如一个叫 work 用来处理日常开发,一个叫 logs 一直挂着查看日志,一个叫 deploy 专门跑部署任务,互不干扰。会话内部再按任务开窗口,每个窗口内部再按需切分窗格。
2.2 核心概念对应的常用命令
会话层面对应的命令最多,也是日常使用频率最高的。创建会话用 tmux new -s 会话名;查看当前服务器上有哪些会话用 tmux ls 或者 tmux list-sessions;重新接入一个已有会话用 tmux attach -t 会话名。
窗口是会话里面的横向标签页,组合键基本都带前缀。窗格是把一个窗口分成多个小区域,组合键也都带前缀。后面我分开讲窗口和窗格的具体操作。
有一点需要特别强调:命令和组合键有区别。命令是在shell里输入的那些以 tmux 开头的语句,比如 tmux ls,而组合键是先按前缀键(默认是 Ctrl+b,也就是先同时按住Ctrl和b,松开后再按下一个键)再按功能键,比如 Ctrl+b c 表示创建新窗口。理解这两种操作方式的差异,后面查资料就不会混乱。
3. 基础命令速查:从创建到恢复,一条条聊
3.1 必背命令速查表
我直接把最常用的命令整理成一张表,基本能满足日常90%的场景。
| 命令或组合键 | 作用 | 一句话说明 |
|---|---|---|
| tmux new -s name | 创建新会话 | 新建名为 name 的会话 |
| tmux new -s name -d | 后台创建会话 | 创建后不直接进入,适合脚本 |
| tmux ls | 查看所有会话 | 显示会话名、窗口数、创建时间 |
| tmux attach -t name | 接入已有会话 | 断线重连后的第一选择 |
| tmux attach | 接入最近会话 | 只有一个会话时比较方便 |
| 前缀 d | 分离当前会话 | 会话留在后台,返回普通shell |
| tmux detach | 分离当前会话 | 效果同上,命令行版 |
| tmux kill-session -t name | 杀死指定会话 | 直接结束会话及其中任务 |
| tmux kill-server | 停止所有会话 | 慎用,会关掉所有会话 |
| tmux list-keys | 查看所有快捷键 | 自定义时先看默认绑定 |
| 前缀 ? | 查看快捷键列表 | 在tmux里直接弹出帮助 |
这里有个细节值得说:分离(detach)和退出(exit)完全是两回事。分离后会话还在后台继续跑,你随时可以 tmux attach 回去;而如果直接在某个窗口里输入 exit 或者关闭最后一个窗格,整个会话也就结束了。想临时离开但又希望任务继续跑,一定要用 前缀 d 分离,而不是直接关闭终端。
3.2 一次完整的会话生命周期演示
假设我现在要开始处理一个需要长期跑的数据处理任务,常规做法是这样:先开一个会话。
tmux new -s dataprocess接着在会话里启动我的处理脚本:
python3 process_data.py脚本开始跑的时候我就可以放心地看着日志。如果这时有事要离开,按 前缀 d 分离会话,终端会回到普通shell,屏幕上还会提示类似 [detached (from session dataprocess)] 的信息。第二天回来重新登录服务器后,执行:
tmux attach -t dataprocess就能看到昨天的任务还在跑,实时输出还在继续。任务结束后如果确定不再需要这个会话,可以在会话里输入:
exit或者在shell里直接执行:
tmux kill-session -t dataprocess这样一次完整的会话生命周期就闭环了。
如果希望会话一创建就在后台运行,比如写脚本批量创建会话,可以这样:
tmux new -s batch -d tmux attach -t batch-d 参数的意思是 detached,通常配合脚本或者自动初始化场景。写脚本时还有个常见需求:创建会话时不光要进入会话,还想自动执行几条命令,这时 tmux send-keys 就派上用场了。比如:
tmux new -s deploy -d tmux send-keys -t deploy 'cd /opt/project' C-m tmux send-keys -t deploy './deploy.sh' C-m tmux attach -t deploy这里的 C-m 表示回车。tmux 中很多控制键都写作 C-xxx 的形式,比如 C-m 回车、C-c 中断、C-z 挂起。脚本化tmux时这些细节能省不少事。
4. 窗口和窗格:真正提升效率的组合键操作
4.1 窗口管理的核心组合键
一个会话里可以开多个窗口,每个窗口都是一个独立的"工作页面",相互之间可以快速切换。最常用的窗口操作如下:
| 组合键 | 作用 | 备注 |
|---|---|---|
| 前缀 c | 创建新窗口 | c 是 create |
| 前缀 , | 重命名当前窗口 | 命名后方便切换识别 |
| 前缀 n | 切换到下一个窗口 | 相当于右翻页 |
| 前缀 p | 切换到上一个窗口 | 相当于左翻页 |
| 前缀 数字(0-9) | 直接跳转到对应编号窗口 | 窗口太多时不推荐硬记编号 |
| 前缀 w | 列出所有窗口 | 弹出列表,可上下选择后回车进入 |
| 前缀 f | 在窗口里查找关键字 | 根据窗口名搜索,适合窗口多时 |
| 前缀 & | 关闭当前窗口 | 会提示确认输入y |
窗口管理的核心逻辑是:每个窗口相当于一个独立的标签页,会话只是这些标签页的容器。在窗口里执行的任务互不影响,比如我经常开三个窗口,一个写代码、一个跑测试、一个看日志,用 前缀 n/p 来回切,比在系统层开好几个终端标签页省心得多。
如果窗口数量比较多,建议创建窗口时顺手用 前缀 , 重命名,不然一堆默认名称的窗口切换起来很容易迷路。比如我正在处理多个项目时,会按项目名给窗口命名,切换到哪个窗口心里有数。
4.2 窗格分割与切换
窗格操作是tmux相比普通标签页最大的优势。你可以把一个窗口切分成多个区域,同时展示不同的内容。默认的切分方式有两种:
- 前缀 %:垂直分割,在当前窗格右侧开一个新窗格,形成左右布局。
- 前缀 ":水平分割,在当前窗格下方开一个新窗格,形成上下布局。
注意键盘上的双引号键是Shift+单引号,不要按错。分割之后,在多个窗格之间切换用 前缀 + 方向键,方向键指向哪个方向就切到哪个方向的窗格。如果想按照顺序轮换窗格,用 前缀 o。
窗格多了之后容易找不到焦点,可以按 前缀 q,tmux会临时在每个窗格上显示一个数字编号,按下对应数字键就能直接跳转到对应窗格。这个功能在窗格数超过3个时特别实用。
关闭某个窗格用 前缀 x,关闭前会询问是否确认,输入y执行。如果只想临时把一个窗格放大到全屏,按 前缀 z,再按一次恢复原样,相当于这个窗格的"全屏/还原"开关。
4.3 布局切换与窗格大小调整
窗格分割多了之后,布局可能变得很乱。tmux内置了几种常见布局,用 前缀 + 空格键 可以在预设布局之间循环切换:水平平铺、垂直平铺、主区域加辅助区域等。循环几次基本能找到合适的样子。
调整窗格大小也是高频操作。默认方式是基于 前缀 + Ctrl + 方向键 的组合:按住前缀和Ctrl不放,再按方向键,就可以连续向对应方向扩大当前窗格。调整得差不多就松手。这种方式比较直观,但说实话调起来略慢,很多人会改用命令行方式精确调整窗格大小。例如:
tmux resize-pane -D 10这条命令把当前窗格向下扩大10行。同理,-L 向左、-R 向右、-U 向上。如果想按百分比调整,可以配合 -p 参数。用命令方式的好处是精确可控,适合在脚本里自适应布局。
还有一个实用操作是 前缀 + !,可以把当前窗格"弹出"成为一个独立窗口。反之,窗口里想再拆出窗格时,就用前面说的 前缀 % 或 前缀 "。
5. 复制模式、滚动查看与系统剪贴板联动
5.1 先会滚动屏幕再谈复制
很多新手翻tmux里的历史输出时一脸懵:直接用滚轮或方向键,发现根本滚不动。原因在于,tmux默认并没有进入滚动模式,终端输入都直接交给当前前台进程处理。
最原始的方式是进入复制模式:按 前缀 + [,进入后就可以用 方向键、PgUp、PgDn 等翻看历史内容。查看结束后按 q 退出复制模式,回到正常交互。
如果你觉得每次都要进复制模式太麻烦,强烈建议在配置里开启鼠标模式:
set -g mouse on开启之后,直接用鼠标滚轮就能滚动查看历史输出,也可以直接点击窗格切换焦点,还能拖动窗格边框调整大小。我个人认为对于大多数使用者来说,鼠标模式是tmux配置里性价比最高的一项,开了之后学习成本骤降。
5.2 复制:从tmux缓冲区到系统剪贴板
鼠标模式开启后,按住 Shift 再用鼠标选中文本,通常能直接复制到系统剪贴板。不过不同终端软件行为略有差异,不算稳定。tmux自己有一套独立的缓冲区机制:复制的内容会存到tmux的缓冲区(buffer)里,默认不会自动同步到系统剪贴板。
在非鼠标模式下复制文本的流程是这样:进入复制模式(前缀 [),移动光标到起点,按 空格键 开始选择,移动光标选中内容,最后按 回车 完成复制并自动退出复制模式。之后按 前缀 + ],就会把缓冲区内容粘贴回当前终端。
如果希望复制模式使用vi风格的按键,需要在配置里设置:
setw -g mode-keys vi设置之后,复制模式里可以用 v 开始选择、y 复制并退出、/ 进行搜索,方向键也能换成 hjkl。这套按键对用过vim的人来说几乎零学习成本。
5.3 把内容真正送进系统剪贴板
tmux缓冲区只是tmux自己的内部粘贴板,跟系统级剪贴板是两套体系。想复制终端里的内容出来贴到浏览器或编辑器,需要手动做一步桥接。最简单的做法是利用 tmux show-buffer 命令:
tmux show-buffer -b buffer名 | pbcopy # mac tmux show-buffer -b buffer名 | xclip -selection clipboard # linux但每次复制完还要跑一遍命令,实在麻烦。更优雅的做法是在配置里绑定快捷键,让复制动作直接通过管道进入系统剪贴板。以Linux为例,安装xclip后可以这样绑定:
bind-key -T copy-mode-vi v send-keys -X begin-selection bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xclip -selection clipboard"两条命令的意思是:在vi模式的复制模式下,按 v 进入选择,按 y 复制并传送到xclip,同时退出复制模式。这样在tmux里选中内容,出来之后直接就能Ctrl+V粘贴到其他软件。mac用户把 xclip 换成 pbcopy 即可。
这里有个小小的注意事项:复制模式里按 y 之后,如果系统里没装 xclip,复制动作会失败,建议先用命令行确认工具装好再绑定。
6. 配置文件定制:让tmux变得更顺手
6.1 常用配置项解析
tmux的配置文件默认位于 ~/.tmux.conf,修改后需要重新加载。加载方式有两种,一是退出全部tmux会话后重启,二是在会话里执行:
prefix + :然后输入:
source-file ~/.tmux.conf按回车生效。为了方便日常调试,很多人会绑定一个快捷键专门用于重新加载配置,例如在配置文件里加一行:
bind r source-file ~/.tmux.conf这样以后改完配置,直接按 前缀 + r 就能生效,非常方便。
下面列几个我认为新手上路必配的选项:
set -g prefix C-a这一行把默认前缀 Ctrl+b 改成 Ctrl+a。是否要改因人而异,C-b在bash里默认是"光标向左移动一个字符",如果平时在终端里频繁用这个快捷键,改掉前缀能避免很多冲突。不过改了之后也有代价:bash里Ctrl+a原本是"光标移到行首",也会被占用。我的建议是,如果不觉得冲突,保持默认C-b就好;如果确实频繁用到行首移动,可以通过其他方式绕开,比如在终端软件层面重映射键位。
set -g mouse on开启鼠标支持,前面已经说过,这是降低上手成本最重要的一项。
set -g history-limit 50000把每个窗格的滚动历史行数从默认的两三千行提高到5万行,长日志不至于翻不到前面的内容。注意这个选项只对新建窗格生效,已经存在的窗格要保持原样,所以在创建会话之前就配好最稳妥。
set -g base-index 1 setw -g pane-base-index 1把窗口和窗格编号从0改成从1开始。很多人不习惯从0开始计数,改掉之后窗口数字更直观。
setw -g mode-keys vi把复制模式改成vi按键风格,上一部分已经提过。
set -g default-terminal "screen-256color"设置tmux内部的终端类型。如果你在tmux里跑vim、htop等工具时发现颜色异常,通常会考虑这个设置。加了这个后,tmux内部程序会认为自己在支持256色的终端里运行,从而正确显示配色。
6.2 状态栏里放什么内容
tmux默认底部状态栏会显示会话名、窗口列表、时间等信息。利用配置可以按自己的习惯调整。例如:
set -g status-left "[#S]" set -g status-right "#(whoami)@#h | %H:%M"第一行让左下角显示当前会话名,便于多会话时一眼看清自己在哪里。第二行让右下角显示用户名、主机名和时间。中间窗口列表可以在后面加上样式:
set -g window-status-current-style fg=black,bg=green把当前活跃窗口标记为绿底黑字,其他窗口保持默认。状态栏改起来可玩性很高,也容易折腾,我的经验是先保持简洁,把关键信息显示出来就够了,不要堆太多内容导致状态栏太长遮挡实际输出。
6.3 插件:从零开始装tpm
tmux本身功能已经很强,但一些进阶能力可以通过插件扩展。推荐先装tpm(Tmux Plugin Manager),它相当于tmux的包管理器,之后就可以用一条配置安装其他插件。
安装tpm的方法不复杂,在 ~/.tmux.conf 里加入:
set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' run '~/.tmux/plugins/tpm/tpm'然后重启tmux,按 前缀 + I 安装配置里列出的插件。
我这边实际用下来比较推荐两个插件。一个是 tmux-resurrect,可以保存当前会话的所有窗口、窗格、命令状态,重启机器后自动恢复,跑长任务时能多一道保险。另一个是 tmux-continuum,它让tmux在后台自动定期保存状态,重启后自动恢复,配合resurrect用效果更好。要注意的是,恢复的进程命令不一定能百分百精确还原,比如某些状态复杂的交互式程序,恢复后可能仍需要手动介入,但这个兜底机制已经很实用了。
7. 常见的坑与排查技巧实录
7.1 SSH断开重连后窗口大小不对
客户端断开重连之后,tmux窗口有时没有立即跟随终端尺寸自适应,导致画面内容排版错乱。如果遇到这种情况,可以先在会话里执行:
tmux refresh-client让tmux重新检测当前客户端尺寸。部分旧版本可能需要用:
tmux detach tmux attach强制重连更能彻底刷新。多数情况下重新attach一次就能恢复正常。
7.2 tmux里vim或htop颜色不对,或者显示成乱码
这类问题的根源基本都在终端类型(TERM)上。在tmux里查看一下环境变量:
echo $TERM如果输出不是 screen 或 screen-256color 相关值,颜色自然会显示不完整。在配置文件里加一次:
set -g default-terminal "screen-256color"然后重新加载配置并新开窗口验证。颜色还不对的话,检查SSH客户端本身是否支持256色,比如某些终端软件默认只开16色。vim场景下,还要在vim配置里加上:
set t_Co=256这样vim才能感知到256色环境并加载对应配色。
7.3 脚本或者定时任务里调用tmux报错
在非交互shell里直接执行 tmux new -s xxx 有时会报错,原因通常是tmux找不到可用的终端设备,或者TMUX环境变量没有正确设置。解决办法是在命令里显式指定:
tmux new-session -d -s name-d 会让tmux在后台创建会话,不依赖当前终端交互。如果是在一个已经存在的tmux会话内再开一个会话,也需要先把外层会话分离出来,或者明确指定新会话名,避免和当前会话混淆。
7.4 在tmux里面又开了一个tmux
在某些场景下你会遇到嵌套tmux的情况,比如先SSH到跳板机,再SSH到目标机,两层都开了tmux。这时内层tmux的前缀键默认也是Ctrl+b,按一下Ctrl+b往往作用在外层tmux上,操作会很混乱。
解决思路有几个。一是给内层tmux改一个不同的前缀键,和本机习惯区分开。二是在外层tmux配置里绑定一个转发键,让前缀键可以直接传给内层:
bind-key -T root C-b send-prefix这条命令可以让外层tmux识别到前缀键时,把按键内容直接透传给内层tmux。更省事的做法是干脆不在内层再开tmux,SSH进入目标机后直接 attach 外层会话,减少一层嵌套。
7.5 多个窗格想同步输入同样的命令
有时候需要同时登录多台机器执行同样的命令,tmux的 synchronize-panes 功能正好干这个。在会话里执行:
prefix + :然后输入:
setw synchronize-panes on开启后,在一个窗格输入的内容会同步出现在所有窗格里。批量修改配置、批量跑同一命令时非常好用。但这里要特别提醒一句:这个功能开启时一定要看清当前有几个窗格,别把含有危险命令的窗格也一起同步执行了,我身边真有人吃过这个亏。
8. 几条让我越用越顺手的配置与习惯
8.1 前缀键的取舍别太较劲
我最初把前缀改成Ctrl+a,确实解决了Ctrl+b和bash移动光标的冲突,但代价是bash里Ctrl+a原本的跳转行首功能没了,后来为了行首跳转又绑了别的键,反而绕。现在我的做法是保留默认前缀Ctrl+b,同时把bash里需要Ctrl+b的场景改为使用其他方式,比如用Ctrl+方向键移动光标,或者干脆配合鼠标。如果你用的终端软件支持键位映射,也可以在终端软件层面把某个不便的键位重映射掉,就不必动tmux的前缀了。
8.2 history-limit要在建会话之前配好
我试过先开了会话再改配置,改完发现老会话的历史行数还是老样子,只能重建会话或者忍受翻不到旧日志。所以现在每次机器初始化,第一件事就是先写 .tmux.conf,然后再开会话。如果你已经开始用了,修改配置后新建会话即可生效,旧会话里的滚动历史还是原样。
8.3 把tmux attach当成默认操作
不管是跑长任务,还是只是临时开个终端,我都习惯在tmux会话里做。SSH断开、电脑休眠都不会影响任务,省心程度非常高。配合 tmux-resurrect 和 tmux-continuum 插件后,即使服务器重启也能恢复原来的工作现场,已经成了我远程开发流程里不可或缺的一部分。
8.4 启动脚本自动铺工作台
分享我常用的一个启动脚本片段,放在服务器上直接用,三段式解决日常开工流程:
tmux new -s work -d tmux send-keys -t work 'cd ~/project && git pull' C-m tmux split-window -h -t work tmux send-keys -t work.1 'tail -f /var/log/app.log' C-m tmux attach -t work这段脚本相当于帮我自动铺好工作台:会话里主窗格进入项目目录,右侧窗格实时看日志,然后一次性attach进去。需要改窗格位置、换命令时,直接改脚本比手动敲组合键要高效得多。
tmux这套工具不难,关键是理解会话、窗口、窗格的结构,再配合一套适合自己的配置和习惯,长期用下来非常省心。希望这篇总结能帮你少走一点弯路,把终端用得更顺手。