screen環境自動構成スクリプト

仕事で複数のサーバを管理しているんだけれど、そのサーバ群に対して1 サーバ / 1 windowでGNU screenを起動してsshでアクセスして管理していたんだ。window配置はこんな感じで。

window番号 ホスト 備考
0 mngr ここにログインして、screenを起動
1 server1 mngrからsshして、zshを起動
2 server2 mngrからsshして、zshを起動

zshを起動しているのは、都合によりデフォルトシェルはbashにしつつも、普段のInteractiveな作業ではzshを使いたかったため。こんなのが必要サーバ台数分続く。そうはいっても最大12台までと決めているけれど。ファンクションキーをwindow切り替えのショートカットとして使っているんで、それ以上はwindowは増やせない。
最初のうちは毎回手でコマンドを打って、1)windowを作って、2)sshして、3)zshを起動する、ってことをしていたんだけど、mngrを再起動すると、またいちから打ち直しなので面倒。やっぱりそこは怠けるべきだと思い、シェルスクリプトで一発でできるようにした。
これがそのスクリプト

#! /bin/bash

# セッション名を設定
s_name='test'

# 接続先ホストリスト
hosts=( \
        'server1' \
        'server2' \
      )

# window名(今回はホスト名の短縮名として設定)
w_names=( \
         's1' \
         's2' \
        )

# mngrだけは0番windowに特別に設定
echo "screen[0]: mngr"
screen -d -m -S $s_name -t 'mngr'
screen -X -S $s_name -p 0 stuff $'zsh\n'


i=1
while [ $i -le ${#hosts[@]} ]
do
    wid=$i
    idx=`expr $i - 1`
    echo "screen[$wid]: ${hosts[$idx]}"
    screen -X -S $s_name screen -t ${w_names[$idx]} $wid
    sleep 1s
    screen -X -S $s_name -p $wid stuff "gsissh ${hosts[$idx]}$(printf '%b' '\015')"
    screen -X -S $s_name -p $wid stuff $'zsh\n'
    screen -X -S $s_name screen -p $wid fit
    i=`expr $i + 1`
done

screen -d -r $s_name -p 0

一番のはまりどころは、screenのwindow内でコマンドを実行するところ。screenにはwindow内でサブプロセスを実行するexecコマンドがあるんだけども、その入出力の挙動がいまいち理解できなかった。ずっと張りっぱなしにしておきたかったsshセッションもいつの間にかに切れてたりしたし。そこで、代替方法としてstuffコマンドでwindowのinput bufferにコマンド文字列+改行を入力する方法をとった。これには「GNU screen を簡単に外側から操作できるようにする Ruby ライブラリ easy-screen」で公開されていたコードを参考にさせていただきました。
さらに、今回はstuffで実行するsshの引数に変数を与えたかったので、シェルの$'...'記法が使えなかった。ここもはまりどころだったんだけど、「Re: sending CRLF via screen -X stuff」を参考に、printfで改行文字を打ち込むことで対応した。