tmux进程管理 tmux

这是一个关于在tmux终端复用器中管理和运行长生命周期进程的技能指南。它详细说明了如何正确复用会话、命名约定、启动和监控进程、生命周期管理以及常见开发场景下的最佳实践。关键词包括:tmux, 进程管理, 开发服务器, 会话复用, 终端复用, DevOps, 命令行工具。

DevOps 0 次安装 0 次浏览 更新于 2/23/2026

name: tmux description: 在tmux中运行长生命周期进程的模式。适用于启动开发服务器、文件监视器、tilt或任何预期会持续运行的进程。

tmux 进程管理

会话复用规则

这些是硬性要求,而非建议:

  • 必须在调用 tmux new-session 前检查 tmux has-session
  • 必须git rev-parse --show-toplevel 派生会话名称,切勿硬编码
  • 必须向现有项目会话添加窗口,切勿创建并行会话
  • 必须使用 send-keys 运行命令,切勿向 new-session 传递内联命令
  • 切勿为当前项目创建新会话(如果已存在)

一个项目 = 一个tmux会话。多个进程 = 该会话中的多个窗口。

交互式Shell要求

使用send-keys模式确保可靠的Shell初始化。 创建会话时会自动生成一个交互式Shell。使用 send-keys 在该Shell内运行命令,确保PATH、direnv和其他初始化正确执行。

# 错误 - 内联命令绕过Shell初始化,破坏PATH/direnv
tmux new-session -d -s "$SESSION" -n main 'tilt up'

# 正确 - 检查会话是否存在,然后在交互式Shell中使用send-keys
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
  tmux new-session -d -s "$SESSION" -n main
fi
tmux send-keys -t "$SESSION:main" 'tilt up' Enter

会话命名约定

始终从项目派生会话名称:

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

对于一个项目中的多个进程,使用窗口而非独立会话:

  • 会话:myapp
  • 窗口:server, tests, logs

启动进程

单个进程

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

if ! tmux has-session -t "$SESSION" 2>/dev/null; then
  tmux new-session -d -s "$SESSION" -n main
  tmux send-keys -t "$SESSION:main" '<命令>' Enter
else
  echo "会话 $SESSION 已存在"
fi

向现有会话添加窗口

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

# 如果窗口不存在则添加新窗口
if ! tmux list-windows -t "$SESSION" -F '#{window_name}' | grep -q "^server$"; then
  tmux new-window -t "$SESSION" -n server
  tmux send-keys -t "$SESSION:server" 'npm run dev' Enter
else
  echo "窗口 'server' 已存在"
fi

多个进程(窗口)

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

# 根据需要创建会话,然后添加窗口
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
  tmux new-session -d -s "$SESSION" -n server
  tmux send-keys -t "$SESSION:server" 'npm run dev' Enter
fi

# 添加更多窗口(幂等操作)
for win in tests logs; do
  if ! tmux list-windows -t "$SESSION" -F '#{window_name}' | grep -q "^${win}$"; then
    tmux new-window -t "$SESSION" -n "$win"
  fi
done
tmux send-keys -t "$SESSION:tests" 'npm run test:watch' Enter
tmux send-keys -t "$SESSION:logs" 'tail -f logs/app.log' Enter

监控输出

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

# 从第一个窗口获取最后50行
tmux capture-pane -p -t "$SESSION" -S -50

# 从特定窗口获取
tmux capture-pane -p -t "$SESSION:server" -S -50

# 检查错误
tmux capture-pane -p -t "$SESSION" -S -100 | rg -i "error|fail|exception"

# 检查就绪指示器
tmux capture-pane -p -t "$SESSION:server" -S -50 | rg -i "listening|ready|started"

生命周期管理

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

# 列出所有会话(查看存在哪些)
tmux ls

# 列出当前会话中的窗口
tmux list-windows -t "$SESSION"

# 仅终止此项目的会话
tmux kill-session -t "$SESSION"

# 终止特定窗口
tmux kill-window -t "$SESSION:tests"

# 向窗口发送按键(例如,Ctrl+C停止)
tmux send-keys -t "$SESSION:server" C-c

隔离规则

  • 切勿使用 tmux kill-server
  • 切勿终止与当前项目不匹配的会话
  • 始终从git根目录或pwd派生会话名称
  • 始终在终止操作前验证会话名称
  • 其他Claude Code实例可能运行着自己的会话

何时使用tmux

场景 使用tmux?
tilt up 是,始终使用
开发服务器 (npm run dev, rails s)
文件监视器 (npm run watch)
测试监视器 (npm run test:watch)
数据库服务器
一次性构建 (npm run build)
快速命令 (<10秒)
需要在对话中直接查看stdout

检查进程状态

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

# 检查会话是否存在
tmux has-session -t "$SESSION" 2>/dev/null && echo "会话存在" || echo "无会话"

# 列出窗口及其状态
tmux list-windows -t "$SESSION" -F '#{window_name}: #{pane_current_command}'

# 检查特定窗口是否存在
tmux list-windows -t "$SESSION" -F '#{window_name}' | grep -q "^server$" && echo "服务器窗口存在"

重启进程

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

# 发送Ctrl+C然后重启命令
tmux send-keys -t "$SESSION:server" C-c
sleep 1
tmux send-keys -t "$SESSION:server" 'npm run dev' Enter

常见模式

如果未运行则启动开发服务器

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

if ! tmux has-session -t "$SESSION" 2>/dev/null; then
  tmux new-session -d -s "$SESSION" -n server
  tmux send-keys -t "$SESSION:server" 'npm run dev' Enter
  echo "在tmux会话中启动开发服务器: $SESSION"
elif ! tmux list-windows -t "$SESSION" -F '#{window_name}' | grep -q "^server$"; then
  tmux new-window -t "$SESSION" -n server
  tmux send-keys -t "$SESSION:server" 'npm run dev' Enter
  echo "向会话添加服务器窗口: $SESSION"
else
  echo "服务器已在会话中运行: $SESSION"
fi

等待服务器就绪

SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)

# 轮询就绪消息
for i in {1..30}; do
  if tmux capture-pane -p -t "$SESSION:server" -S -20 | rg -q "listening|ready"; then
    echo "服务器就绪"
    break
  fi
  sleep 1
done