Skip to content
文档预览图

tmux:从一个例子开始

一个真实的烦恼

凌晨两点,你 SSH 到服务器排查问题,tail -f 正盯着日志,突然 Wi-Fi 断了。重连上去,刚才的 tailvimhtop 全没了——SSH 断开意味着远程 shell 进程被 kill。你重新打开三个终端窗口,重新 cd 到对应目录,重新跑每条命令。

更难受的是,这是第三次了。

tmux 能解决这个问题:让远程程序在 SSH 断开后继续运行,随时重连回来,连窗口布局都不变。

下面我们从零开始把这件事跑通。

第一步:安装

macOS 用 Homebrew 一步到位:

bash
brew install tmux

Linux (Debian/Ubuntu):

bash
sudo apt install tmux

装完验证:

bash
tmux -V
# tmux 3.5a

Windows 用户:tmux 是 Unix 工具,不直接运行在 Windows 上。通过 WSL 安装 Ubuntu,然后在 WSL 里 sudo apt install tmux,用 Windows Terminal 连接。

第二步:创建会话,断开,重连

进到你的项目目录,创建一个命名会话:

bash
cd ~/my-project
tmux new -s dev

你会进入一个看起来"没什么变化"的终端——底部多了一条绿色状态栏。这就是 tmux 里了。

在里面随便做点事:vim main.tstail -f /var/log/syslog

现在模拟"断线"——按 Ctrl-b 然后按 d(detach 的缩写)。你会回到普通终端,状态栏消失,tmux 退到后台。

但刚才的程序没死。用 tmux ls 看一眼:

bash
tmux ls
# dev: 1 windows (created Wed Apr 29 22:15:00 2026)

重新连回去:

bash
tmux attach -t dev

搞定。vim 还是那个 vimtail -f 还在滚动,什么都没丢。

回过头看:刚才发生了什么

整个 tmux 有三层结构,对应三个问题:

Session "dev"            ← 你的工作在哪?一个独立的工作空间
  Window 0: editor       ← 做什么?每个窗口像一个"虚拟桌面"
    Pane 0: vim          ← 怎么看?窗口里的每个分屏
    Pane 1: npm test     ←
  Window 1: logs         ← 切到另一个窗口,干另一件事
    Pane 0: tail -f

这就是 tmux 的全部模型:Session × Window × Pane

Session:工作的"边界"

Session 是 tmux 最顶层的容器。把 session 想象成一个一直活着的终端工作区——你可以随时"走进来"(attach),也可以随时"走出去"(detach),里面的程序一直运行。

命令作用
tmux new -s <name>创建命名会话
tmux ls列出所有会话
tmux attach -t <name>重新连入会话
tmux kill-session -t <name>删除会话

Window:在 session 里切"虚拟桌面"

一个 session 可以装多个 window。每个 window 占满整个屏幕,互相隔离。类比浏览器的标签页——一个查文档,一个写代码,一个跑测试,互不干扰。

快捷键作用
Ctrl-b c创建新窗口
Ctrl-b ,重命名当前窗口
Ctrl-b n下一个窗口
Ctrl-b p上一个窗口
Ctrl-b 0~9跳到第 N 个窗口

Pane:把屏幕切成多块

一个 window 可以切分成多个 pane。每个 pane 是独立的 shell,都能跑不同命令。类比 IDE 里的分屏——左边写代码,右边跑终端。

快捷键作用
Ctrl-b %左右分屏
Ctrl-b "上下分屏
Ctrl-b 方向键在 pane 之间切换
Ctrl-b x关闭当前 pane
Ctrl-b Ctrl-方向键调整 pane 大小

一句收束

所有 tmux 操作都在这个模型里:找到 session → 进入窗口 → 切分面板 → 干活 → detach 走人

第二个例子:开发中的多面板工位

例 1 只解决了"断线不丢"的问题。现在引入对比维度——用一个 tmux session 把开发时需要的所有命令行整合到一个窗口里

场景:你在写一个 Node.js 后端,日常需要同时看四个东西:

  • vim 编辑器
  • npm run dev 的开发服务器
  • npm test -- --watch 的测试监视
  • 一个随时可用的 git 命令行

不用 tmux:四个终端标签页,来回切,切多了就搞混哪个是哪个。

用 tmux 做到"一眼尽收"。创建脚本 ~/dev-layout.sh

bash
#!/bin/bash
tmux new -s backend -d

# 左右分屏:左半给 vim,右半给 dev server
tmux split-window -h -t backend:0
# 向刚创建的右 pane(编号 1)发命令
tmux send-keys -t backend:0.1 'npm run dev' Enter

# 左边上下分屏:上半 vim 不动,下半跑测试
tmux split-window -v -t backend:0.0
tmux send-keys -t backend:0.1 'npm test -- --watch' Enter

# 右下再切一块给 git
tmux split-window -v -t backend:0.2
# 此时右下 pane 的编号是 3
tmux send-keys -t backend:0.3 'git status' Enter

tmux attach -t backend

执行 bash ~/dev-layout.sh,你会看到:

┌─────────────────────┬─────────────────────┐
│ Pane 0: vim         │ Pane 1: npm run dev │
│ (主编辑区)          │ (开发服务器输出)     │
├─────────────────────┼─────────────────────┤
│ Pane 2: npm test    │ Pane 3: git shell   │
│ (测试监视)          │ (随时 git 操作)     │
└─────────────────────┴─────────────────────┘

Ctrl-b 方向键 在四个 pane 之间走动。Vim 里改一行代码,右边 dev server 自动重载,下面测试自动跑——全在同一屏上。

如果 session 还在后台跑着,tmux attach -t backend 回来后布局完好;结束工作时 Ctrl-b d 脱离即可。

这个脚本演示的是 tmux 的脚本化能力——布局不需要每次都手动切。你可以为不同项目各保存一份布局脚本。

单窗口 vs tmux 多面板

维度四个终端标签页tmux 多面板
屏幕利用同时只能看一个四块同屏,尽收眼底
断线恢复全部丢失布局 + 进程都在
复制粘贴需要鼠标选中Ctrl-b [ 进入复制模式,键盘操作
脚本化做不到布局脚本一行 bash 搞定
启动速度手动打开四个标签一行脚本,秒开

第三个例子:用 tmux 搭建 Agent-team 驾驶舱

前两个例子是 tmux 自身的用法。第三个例子拓宽到一个完全不同的维度:用 tmux 编排多个 Claude Code agent session,搭一面实时监控墙

为什么需要驾驶舱

Agent-team 模式下,你同时跑着 3-5 个 teammate——lead 派任务、teammate-A 查日志、teammate-B 读代码、teammate-C 写测试。每个 teammate 是独立的 Claude Code session,有自己的 context window。

最大的风险不是 token 消耗,而是 "指挥不当"——一个 teammate 朝错误方向跑了两小时,而你在另一个 tab 里完全没看见。等你切回来看,它已经烧掉几万个 token 了。

用 tmux 把每个 teammate 放到一个独立 pane 里,一眼扫过去就知道谁在产出、谁卡住了、谁跑偏了。

搭一面 Agent-team 墙壁

配好 setting,进 tmux,对 claude 说人话——只此三步。

1. 配 setting(一次性的)。在 ~/.claude/settings.json 里写:

json
{
  "env": {
    "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
  },
  "teammateMode": "tmux"
}

2. 进 tmux,起 claude。

bash
tmux new -s cockpit
claude

3. 对 claude 说人话。

我想体验 Agent Teams 的 Split panes 效果,请 spawn 3 个队友同时工作:
队友A 负责搜索 Go 1.24 的新特性,
队友B 负责在当前目录创建 hello.go 写一个简单的 HTTP server,
队友C 负责列出当前系统已安装的 homebrew 包数量。
给他们各自的任务后,让他们并行执行。

claude 收到指令,为每个 teammate 自动创建 tmux pane——你什么都不用管,看着就行。

主从关系是怎么建立的

你问 "lead 是怎么把活派给 teammate 的"——答案是 Claude Code 内部全做了:

环节怎么做的
派生 teammate你说 "spawn 3 个队友",Claude Code fork 新 claude 进程
展示teammateMode: "tmux" 让每个 teammate 自动出现在一个独立 tmux pane
派活lead 拆任务写入共享任务列表,teammate 自己去领
agent 间通信内置 mailbox:teammate 调 SendMessage 直接发给 lead 或其他 teammate,自动投递
空闲通知teammate 完成工作或卡住,自动给 lead 发 idle 通知
Ctrl-b 方向键 或鼠标点进各 pane 看进度,也可以直接跟任何 teammate 对话

驾驶舱的操作节奏

  1. 在 lead pane 里说人话——"spawn N 个队友,分别做 A、B、C"
  2. 扫屏。Ctrl-b 方向键 在各 pane 间走动,谁卡了、谁偏了,点进去直接纠正
  3. 回到 lead pane,所有 teammate 的结论已经到了 lead 的对话里,lead 综合输出最终报告

进阶:给驾驶舱配上"监控自动化"

纯靠人眼扫屏还是累。用 tmux capture-pane 做基础监控——定时扫描当前 session 所有 pane 的输出,grep 检测关键信号。因为 teammate 是 Claude Code 动态创建的,pane 不再需要硬编码,直接遍历 tmux list-panes

bash
#!/bin/bash
# ~/agent-monitor.sh —— 每 30 秒扫一遍所有 pane

SESSION="cockpit"

for pane in $(tmux list-panes -t "$SESSION" -F "#{pane_id}"); do
  content=$(tmux capture-pane -t "$pane" -p | tail -5)
  if echo "$content" | grep -q "Error\|Failed\|blocked\|stuck"; then
    echo "$(date): pane $pane 检测到异常信号"
    echo "$content"
    echo "---"
  fi
done

把这个脚本挂到定时任务或另一个 tmux pane 里跑,异常出现时你能第一时间看到,不需要瞪着眼睛盯每一个 pane。

tmux capture-pane -t <target> -p 抓取指定 pane 的文本内容。更多抓取参数(起止行、历史缓冲区)见 man tmux

驾驶舱 vs 单终端窗口:一表对比

维度多个终端窗口tmux 驾驶舱
实时可见每次只能看一个 teammate3-5 个同屏,一眼扫尽
切换成本Alt-Tab / 鼠标点,打断心流Ctrl-b 方向键,低摩擦
断网恢复所有 session 丢失一个 tmux attach 全部回来
布局复用每次手动排列脚本一键重建
程序化监控做不到capture-pane 可抓取文本做自动化检查
Token 浪费风险高——没人盯着的 teammate 可能跑偏两小时低——偏航分钟级被发现

tmux 的输入和输出

tmux 有两套交互界面:快捷键(在 tmux 里用)和命令行(在普通 shell 里用)。

命令行接口

所有 tmux 操作都可以从普通 shell 触发,不需要先进入 tmux:

命令格式用途例子
tmux new -s <name>创建会话tmux new -s dev
tmux attach -t <name>接入已有会话tmux attach -t dev
tmux ls列出会话tmux ls
tmux kill-session -t <name>删除会话tmux kill-session -t old-project
tmux send-keys -t <target> <keys>向 pane 发送按键tmux send-keys -t dev:0.1 'npm test' Enter
tmux capture-pane -t <target> -p抓取 pane 文本tmux capture-pane -t dev:0.0 -p
tmux split-window -h -t <target>水平分屏tmux split-window -h -t dev:0

快捷键(默认前缀:Ctrl-b

进入 tmux 后,所有快捷键以 Ctrl-b 开头(先按 Ctrl-b,松开,再按下一个键):

快捷键类别作用
Ctrl-b d会话detach,脱离当前会话
Ctrl-b $会话重命名当前会话
Ctrl-b s会话列出所有会话,可切换
Ctrl-b c窗口创建新窗口
Ctrl-b ,窗口重命名当前窗口
Ctrl-b n / p窗口下一个 / 上一个窗口
Ctrl-b 0~9窗口跳到第 N 个窗口
Ctrl-b &窗口关闭当前窗口(需确认)
Ctrl-b %面板左右分屏
Ctrl-b "面板上下分屏
Ctrl-b 方向键面板在面板间切换
Ctrl-b x面板关闭当前面板(需确认)
Ctrl-b Ctrl-方向键面板调整面板大小
Ctrl-b z面板当前面板全屏 / 还原
Ctrl-b { / }面板面板左右互换位置
Ctrl-b Space面板循环切换布局样式
Ctrl-b [其他进入滚动 / 复制模式(q 退出)
Ctrl-b ?其他查看所有快捷键

tmux 命令模式

在 tmux 里按 Ctrl-b : 进入命令模式,可以输入任何 tmux 命令(不用加 tmux 前缀):

Ctrl-b :
:new-window -n logs
:split-window -h
:resize-pane -L 10

所有在 shell 里 tmux xxx 的命令,在命令模式里去掉 tmux 直接用。适合快捷键记不住或需要加参数的操作。

配置放在哪

tmux 的配置只有一个文件:

路径作用域是否进 Git
~/.tmux.conf当前用户,所有会话可以(用 dotfiles 仓库管理)
~/.config/tmux/tmux.conf同上(XDG 风格)可以

如果两个文件都存在,tmux 优先读 ~/.tmux.conf

经验法则.tmux.conf 放通用配置(键位、外观、鼠标)。不要在这里写项目特定的会话脚本——那些放各自的 ~/project-layout.sh 里,只跟项目走。

进阶:几个值得知道的细节

鼠标支持

默认情况下 tmux 支持鼠标点击切换 pane 和拖拽调整分隔线。如果没有,在 ~/.tmux.conf 里加:

set -g mouse on

加了之后:鼠标滚轮翻历史输出、左键点 pane 切换焦点、拖拽分隔条调整大小。

把前缀改成更顺手的键

Ctrl-b 对很多人来说手指跨度大。改成 Ctrl-a(GNU Screen 用户熟悉这个)或反引号 `(伸手即得):

# ~/.tmux.conf
set -g prefix C-a
unbind C-b
bind C-a send-prefix

改完之后,本文所有 Ctrl-b 换成你的新前缀。

复制粘贴(不依赖鼠标)

tmux 有内置的复制模式,完全键盘操作:

  1. Ctrl-b [ 进入复制模式
  2. 方向键移动光标到起始位置
  3. Ctrl-Space 开始选中(v3.4+;老版本用 Space
  4. 方向键选中区域
  5. Enter 复制并退出
  6. Ctrl-b ] 粘贴

如果想把 tmux 里复制的内容同步到系统剪贴板,需要装 reattach-to-user-namespace(macOS)或 xclip(Linux):

# macOS: ~/.tmux.conf
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "pbcopy"

# Linux: ~/.tmux.conf
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xclip -selection clipboard"

嵌套 tmux:在一个 tmux 里连到另一台机器上的 tmux

场景:本地开了 tmux,SSH 到服务器上也开了 tmux。两个 Ctrl-b 冲突。

解法:把内层 tmux 的前缀按键发给外层,按两次 Ctrl-b

bind -T prefix C-b send-keys C-b

第一次 Ctrl-b 被外层捕获,第二次 Ctrl-b 作为普通按键发给内层。

列出所有 pane 并做批量操作

bash
# 列出当前 session 所有 pane 的 ID 和路径
tmux list-panes -t dev -F "#{pane_id} #{pane_current_path}"

# 向所有 pane 发送同一条命令
tmux list-panes -t dev -F "#{pane_id}" | xargs -I {} tmux send-keys -t {} 'echo hello' Enter

这在驾驶舱里配合上面的监控脚本一起用——异常 pane 不用手动切进去,直接 send-keys 发指令纠偏。

调试

  • tmux ls — 最基础的排错命令。如果 attach 失败,先看会话是不是还在
  • tmux info — 查看当前 tmux 服务器信息(版本、socket 路径、活跃 session 数)
  • tmux show-options -g — 查看所有全局配置,确认你的 .tmux.conf 改动是否生效
  • 快捷键没反应:八成是前缀冲突或被其他终端快捷键拦截了。用 tmux show-options -g | grep prefix 确认当前前缀
  • Ctrl-b : 然后输入 display-message "hello" 验证前缀是否正常工作
  • 配置文件改了没生效:tmux source-file ~/.tmux.conf 手动加载,或者在 tmux 里 Ctrl-b : 然后 source-file ~/.tmux.conf

速查

# 会话
tmux new -s <name>          # 新建命名会话
tmux attach -t <name>       # 重连会话
tmux ls                     # 列出会话
Ctrl-b d                    # 脱离当前会话

# 窗口
Ctrl-b c                    # 新建窗口
Ctrl-b 0~9                  # 跳到第 N 个窗口
Ctrl-b ,                    # 重命名窗口

# 面板
Ctrl-b %                    # 左右分屏
Ctrl-b "                    # 上下分屏
Ctrl-b 方向键                # 切换面板
Ctrl-b z                    # 全屏 / 还原
Ctrl-b x                    # 关闭面板

# 复制粘贴
Ctrl-b [  → 方向键 → Space  → 方向键选中 → Enter 复制
Ctrl-b ]                    # 粘贴

# Agent-team 驾驶舱
"teammateMode": "tmux"          # ~/.claude/settings.json 配置展示模式
"请 spawn 3 个队友同时工作…"      # 在 tmux 里对 claude 说人话,pane 自动出现
tmux capture-pane -t <pane> -p  # 抓取 pane 文本内容做监控

# .tmux.conf 必加
set -g mouse on             # 鼠标支持
set -g prefix C-a           # 改前缀(可选)