Tmux 会话持久化:Resurrect 与 Continuum 配置
Tmux 会话持久化:tmux-resurrect + tmux-continuum
概述
通过 tmux-resurrect + tmux-continuum 实现:
- 手动 或 自动 保存完整的 tmux 环境(会话、窗口、面板、布局、工作目录)
- 重启系统后 自动恢复 tmux 会话
- 可选:恢复面板中 正在运行的程序
基本配置
在 ~/.tmux.conf 中添加:
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
# 每 15 分钟自动保存
set -g @continuum-save-interval 15
# 启用自动恢复(tmux 启动时自动恢复上次会话)
set -g @continuum-restore on
# 启用开机自启(通过 systemd)
set -g @continuum-boot on
安装后 prefix + I 拉取插件,然后 tmux source-file ~/.tmux.conf 重载。
保存文件位置
~/.local/share/tmux/resurrect/
├── tmux_resurrect_20260719T164714.txt # 历史保存文件
├── tmux_resurrect_20260720T104253.txt
├── ...
└── last -> tmux_resurrect_20260720T233636.txt # 符号链接指向最新保存
可通过 set -g @resurrect-dir '/custom/path' 自定义保存目录。
保存文件格式
每行用 tab 分隔,行首标识类型:
pane 行
pane {session} {window} {active} {flags} {pane_idx} {title} :dir {is_active} {command} :{full_command}
{command}— tmux 的#{pane_current_command},即面板中运行的程序名{full_command}— 保存策略捕获的完整命令行(以:开头,空则为:)
window 行
window {session} {idx} :name {active} :flags {layout} {:auto_rename}
state 行
state {client_session} {client_last_session}
关键机制
自动保存流程
continuum.tmux被加载时,将continuum_save.sh注入到status-right中- 每隔
@continuum-save-interval分钟触发一次保存 save.sh收集所有面板信息并写入保存文件- 如果与上次内容相同则跳过(不更新
last符号链接),避免无意义的文件增长
自动恢复流程
- tmux 服务启动时,
continuum.tmux检测just_started_tmux_server - 调用
continuum_restore.sh(后台执行,延迟 1 秒等待插件加载) - 检查
@continuum-restore on且无其他 tmux 服务器在运行 - 调用
restore.sh重建会话、窗口、面板 - 恢复窗口布局、标题、活动面板等
系统自启动(systemd)
当 @continuum-boot on 时:
- tmux 启动时自动创建
~/.config/systemd/user/tmux.service - 运行
systemctl --user enable tmux.service - 系统启动时通过 systemd 启动 tmux(
new-session -d) - tmux 启动后自动触发恢复
程序恢复
默认行为
默认只恢复以下程序:
vi vim view nvim emacs man less more tail top htop irssi weechat mutt
自定义恢复列表
# 增加更多程序
set -g @resurrect-processes 'ssh psql mysql sqlite3'
# 程序名包含参数时需要引号
set -g @resurrect-processes 'some_program "git log"'
# 恢复所有程序(谨慎使用)
set -g @resurrect-processes ':all:'
# 不恢复任何程序
set -g @resurrect-processes 'false'
高级匹配语法
| 语法 | 说明 |
|---|---|
~program |
模糊匹配,program 出现在命令行任意位置即匹配 |
program->cmd |
替换恢复命令(原本的 program 替换为 cmd 执行) |
cmd * |
保留原始参数 |
~rails->rails server * |
组合:匹配 rails,用 rails server + 原参数恢复 |
示例:
# 匹配 'rails server' 的完整路径,恢复时用简洁命令
set -g @resurrect-processes '"~rails server->rails server *"'
Vim/Neovim 会话恢复
tmux-resurrect 内置 vim/nvim 会话策略。恢复时自动查找并加载 Session.vim 文件。
需要配合 vim 的 session 插件(如 tpope/vim-obsession 或 neovim 的 :mksession)。
保存策略对比
| 策略 | 文件 | 原理 |
|---|---|---|
ps (默认) |
ps.sh |
ps -ao ppid,args 查找 pane PID 的直接子进程 |
pgrep |
pgrep.sh |
pgrep -lf -P $PID 查找直接子进程 |
linux_procfs |
linux_procfs.sh |
通过 /proc 读取,与 ps 类似 |
deep_leaf (自定义) |
deep_leaf.sh |
tty + 进程树深度搜索,更准确 |
deep_leaf 策略详解
问题:默认 ps 策略只能捕获 pane PID 的直接子进程。如果 shell 中运行前 台命令,该命令是 shell 的直接子进程,可以正常捕获。但如果有进程嵌套 (如 npm start → node server.js),或 shell 有多个子进程,可能捕获错误。
解决方案:deep_leaf 策略通过以下步骤精确找到前台命令:
- 获取 pane PID 所在的 tty(如
pts/1) - 列出该 tty 上所有处于前台进程组(stat 含
+)的进程 - 过滤掉 shell 进程(zsh/bash/fish 等)
- 选择离 pane PID 最近的进程
- 读取
/proc/PID/cmdline获取完整命令行
回退机制:如果 tty 方式失败(如 tty 为 ?),则递归搜索所有后代进程, 找到最深的非 shell 叶子进程。
常见问题与解决
1. 重启后会话无法恢复
原因排查:
- 检查
@continuum-restore on是否设置 - 检查
~/.local/share/tmux/resurrect/last符号链接是否有效 - 手动执行恢复脚本测试:
~/.tmux/plugins/tmux-resurrect/scripts/restore.sh - 确认没有
~/tmux_no_auto_restore停用文件
如果希望开机自动启动 tmux:确保 @continuum-boot on 已设置,且 systemd 服务已启用(systemctl --user is-enabled tmux.service)。
2. 恢复后每个面板显示 %
这是 zsh 的 PROMPT_SP(部分行标记)。当终端输出不以换行结尾时,zsh 显示 % 提示。
解决:在 ~/.zshrc 中添加:
1 | |
3. 恢复后程序/命令丢失
根本原因:tmux-resurrect 只能保存和恢复面板的初始进程(通过 pane_full_command 字段)。对于从 shell 中交互式启动的命令:
- 如果命令是 shell 的直接子进程且在前台运行 → 保存策略可以捕获
- 如果保存时面板空闲(没有前台命令)→
pane_full_command为空,无法恢复 - 如果命令进程嵌套多级 → 需要用
deep_leaf策略
最佳实践:
- 对于需要持久化的服务,使用
tmux new-window 'command'直接创建 - 配合 vim/nvim 的 session 机制
- 使用
@resurrect-processes ':all:'搭配deep_leaf策略
4. continu.tmux 中有 set -x
插件文件 continuum.tmux 第 3 行如果有 set -x,会导致每次加载时输出 大量 bash 调试信息。应删除该行。
5. 保存文件目录权限
保存目录 ~/.local/share/tmux/resurrect/ 需要有读写权限。 如果目录不存在或不可写,保存会静默失败。
6. 切换默认 shell 后的兼容性
如果从 fish 切换到 zsh(或其他 shell),旧保存文件中的 pane_command 仍然 显示为 fish。但这不影响恢复,因为恢复时使用当前的 default-shell 配置。 只需更新 ~/.tmux.conf 中的 set -g default-shell /usr/bin/zsh。
手动操作
1 | |
调试技巧
1 | |