tmux では kill-session でセッション内の window を終了させることができるが、この場合、問答無用で HUP シグナルが送られる。
しかし、アプリケーションによっては INT シグナルを送ったり、exit とタイプしないと正常な終了処理が行われない場合がある。
現在のセッションのすべての window について、名前に基づいて適切な終了処理を行う tmkill という Ruby スクリプトを作成した。
# !/usr/bin/env ruby
# tmux のウィンドウを安全に kill する
# ウィンドウ名にもとづいて exit [Enter] か control-c を送る
# セッション名・ウィンドウ名の取得
# #{} は tmux のフォーマット文字列
session = `tmux display-message -p "\#{session_name}"`.strip
window_names = `tmux list-windows -F "\#{window_name}"`.strip.each_line.map{|l| l.strip }
commands = []
window_names.each do |window|
# ウィンドウ名に基づいて、送信するキー入力を決定する
# ウィンドウ名の最初に [test] とついていれば、それを省く
keys = case window.gsub(/^\[test\]/, "")
when "guard", "rails-sh"
%w(exit Enter)
when "rails", "resque", "solr", "wordpress"
%w(C-c)
else
# ignore
next
end
commands << ["tmux", "send-keys", "-t", "#{session}:#{window}"] + keys
end
if (ARGV & %w(-n --dry-run)).any?
require "shellwords"
commands.each{|cmd| puts cmd.shelljoin }
else
commands.each{|cmd| system *cmd }
end
kill-session と違ってセッション自体は終了させない。
また名前がマッチしない場合は何もしないようにして、シェルは終了させないようにしている。
解説
tmuxinator を使ってる場合にだいたい同様の事を実現している記事 (Exit Tmuxinator Session Safely) を参考にした。
まず、現在のセッション名を取得する。
# tmux display-message は status line の表示
# -p で標準出力へ表示
# #{session_name} はセッション名を示すフォーマット文字列
$ tmux display-message -p '#{session_name}'
0
ウィンドウ名を取得する。
# tmux list-windows は現在のセッションのウィンドウ一覧の表示
# -F でフォーマットが指定できる
# #{window_name} はウィンドウ名を示すフォーマット文字列
$ tmux list-window -F '#{window_name}'
zsh
rails
guard
tmux send-keys
コマンドでそれぞれのウィンドウにキー入力を送る。
# tmux send-keys -t セッション名:ウィンドウ名 キー入力1 キー入力2 ...
$ tmux send-keys -t 0:rails C-c
$ tmux send-keys -t 0:guard exit Enter