GNU Screenを改造してhardstatusを積極的に使う

今時はTmuxを使うらしいですが、GNU Screenでもうちょっとがんばってみます。今回はScreenを少しだけ改造してzshとの相性を強めてみました。


Screenのウィンドウタイトルを直前に実行したコマンドで更新している人は多いと思います。最近まで私もそうしていました。シェルがzshならpreexec内でscreen用のエスケープコードを出力するのが定番でしょうか。この方法の欠点はエスケープコードがscreen専用なので、何も対策をしていないと、例えばxtermから直接アクセスした時に変なエコーバックが表示されてしまうところです。もちろん、普通は環境変数をみてscreenから繋いでるときだけウィンドウタイトルの更新を行うように設定しているでしょうから、大抵は問題になりません。手元の.zshrcでも$STYという変数をみて切替を行っていました。なんで$TERM見ないのっていう意見もあるかもしれませんが、歴史的経緯によってScreen上でもxterm-256colorになってる人も多いかと思います。この場合、少なくとも私が知る範囲では$STYを見るぐらいしかScreen経由でシェルを起動しているかを見分ける方法がありません。

さて、この状況で困るのがSSH先のシェルからは接続元のシェルがScreen経由で起動されているかどうかを簡単に見分ける方法が無いことです。見分けが付かない場合は安全側に倒すのが普通ですから、SSH先のシェルからローカルScreenのタイトルを更新することが出来ません。こうなると沢山SSHの接続ウィンドウを開いて、特に同じホストが多かったりする場合に困ります。ウィンドウタイトルがみんな同じになってしまうので、どのウィンドウで何をしていたのかが分からなくなってしまい、しばしば迷子になるのです。できればローカルでコマンドを打ったときのように、リモートのシェル内で打ったコマンドをScreenのウィンドウタイトルに反映したいところです。でもでも、リモート側ではScreen経由かどうか見分けが付かないのでエスケープコードを出すわけにもいかず、それは夢という事になってしまいます。

解決策はhardstatusを使うことです。普段ウィンドウタイトル(.screenrcでいうところの%t)を使っていると忘れがちですがScreenではhardstatus(%h)の値も使うことが出来ます。hardstatusの値はネイティブな(?)ターミナル、例えば本当のxtermやTerminal.appにおけるウィンドウのタイトル部分に設定されるべき値が代入されています。言い換えれば、ScreenでもxtermでもTerminal.appでも共通のエスケープコードで更新できるのがhardstatusなのです。もちろん世の中にはxterm意外にも色々なターミナルがあるので、そういうものを使ってる人には通用しないのですが、少なくとも普段xterm互換のターミナルしか使っていない私のような人間には、Screenでもなんでも対応できるエスケープコード(\e]0;)は便利なわけです。

ただ、%h変数には1つ問題があります。それは%tに対する%wに当たる変数が存在しないことです。%wはアクティブなウィンドウ以外のウィンドウリストですから、これに対応する変数が存在しないということは、hardstatusだけではウィンドウリストが作れないと言うことです。アクティブなウィンドウの分は%hで済みますが、他のウィンドウのhardstatusが取れなければ結局%tに、つまりはScreen依存のエスケープコードに依存することになります。これは困った。

仕方がないのでScreenを改造して、hardstatus版の%wとして、%Xという変数を追加しました。改造版のコードはgithubに置いてあります。.screenrcにオリジナルの変数を追加すると他のホストで使い回せずに困ることもあるので、%wでhardstatus版のウィンドウリストを表示するように上書きしたoverwrite_wブランチも用意してあります。

そんなわけで、この改造版Screenを使うとSSH先でも安心してウィンドウタイトルの更新が出来るようになります。やりましたね。