2011/01/04

これからの「GNU Screen」の話をしよう

縦分割が目的で使い始めた開発版の GNU Screen。CVS、Subversion、Gitとリポジトリを追いかけていると、他にも便利な機能があることが分かってきました。ここ半年ほど主だった変更はありませんが、4.1.0 のリリースに向けてドキュメントも整備されてきたようですので、2年ほど使用してきて分かってきた変更点をまとめようと思います。

4.1.0における変更点

ここで取り上げる変更点は次の通り。詳細は ChangeLog などを確認してください。

  • 新しい機能
    • 縦分割
    • レイアウト
    • ウィンドウグループ
    • マウス操作のサポート
    • コマンドメッセージの抑止
    • 外部からのコマンド問合せ
  • 拡張されたコマンド/機能
    • 最大ウィンドウ数の増加
    • ウィンドウ番号の相対指定
    • イベント発生ウィンドウの装飾設定
    • 設定で使用可能な変数/書式の追加
    • ウィンドウリスト/画面リストの拡張
  • その他
    • 256色サポート
    • コマンド行の強化
    • コピーモードの検索機能強化

縦分割 (vertical splits)

まずはみんな大好き縦分割から。私もそうですが、この機能を使うために開発版を使いはじめた方も多いと思います。稼働監視として領域をいくつか横に分割して各サーバの top コマンドを表示させるような使い方をしだすと、端末のサイズを広げた分だけ右側のスペースが気になって仕方がありません。縦に分割できるようになれば、ここを有効に活用できるはずです。

従来の領域を分割するコマンド(split)に -v オプションをつけることで縦に分割できます。デフォルトでは |bind されています。

split [-v]

領域を縦にも分割できるようになりましたので、フォーカスの移動(focus)や領域のリサイズ(resize)もそれにあわせて変更されています。

focus {up|down|top|bottom|left|right|prev|next}
いままではどれだけ分割してもフォーカスの移動は上下方向しかありませんでしたが、leftright で左右にも移動できるようになりました。

領域の概念なお、領域の分割は横でも縦でも2分割の組み合わせです。その組み合わせによって nextprev で移動するフォーカスが決まります。右図を例にすると、領域4からフォーカスを移動する場合、up は移動なし、down は領域6、top は領域1、bottom は領域6、left は領域1、right は領域5、prev は領域3、next は領域5 となります。「隣接する次/前の領域へのフォーカス移動」として downup を使っていた場合はそれぞれ nextprev を使う必要があります。

resize [-h][-v][-b] [-p][-l] {[[+-]num]|min|max|=}
領域のリサイズでは変更する方向などを指定できるようになりました。(指定しない場合は今まで通り現在の領域の境界が対象)
  • -h 横方向にサイズを変更します
  • -v 縦方向にサイズを変更します
  • -b 横と縦、両方のサイズを変更します(-h-v相当)
  • -p 領域外のサイズを変更します(領域の分割が横の場合-h、縦の場合-v相当)
  • -l 領域内でサイズを変更します
-l オプションについて補足。resize で領域のサイズを広げる場合、指定した数値にするために他の領域を縮めてしまうことがあります。このオプションを指定すると現在の領域内でリサイズするようになりますので、複雑に分割している領域のサイズを変更するときに意図しない領域が縮小されることを防げます。先の図を例にすると、領域2で :resize -l +10000 とすると領域6は縮まりません。(領域2が縦に目一杯ひろがって(max)、領域1と領域3が高さ1(min)になります)

領域サイズのついでに新しいコマンドを紹介。

focusminsize [ (width|max|_) (height|max|_) ]
でフォーカスがある領域の最低あるべきサイズを指定できます。引数の指定がない場合は現在の設定がメッセージ行に表示されます。デフォルトは :focusminsize 0 0_maxの別名。領域がここで指定したサイズを満たしていない場合、フォーカスした際に指定したサイズまで領域が広がります。フォーカスを失うと元のサイズに戻ります。

縦横にたくさん分割してフォーカスの移動とともに拡大縮小する領域を見るのも面白いですが、個人的には広いサイズが必要ならばレイアウトを使えばいいと思っていますのであまり指定することはないかなと思います。

少し話がそれましたが、縦分割を組み合わせることで今まで MOTTAINAI と思っていたスペースにより多くの情報を表示できますので、作業の効率がますます上がること受け合いです。

レイアウト (layout)

レイアウトについて一言でまとめると、領域に名前をつけて保存できるようにしたもの、と言えます。スクリーンショットだけでは説明しづらいので簡単な図を用いて GNU Screen の基本概念からおさらいします。

クライアント端末から起動された screen プロセスはそれぞれが一つのセッションとして扱われます。デフォルトではセッション生成と同時に一つのウィンドウが作成され、そこでシェル(shell)が実行された状態となります。 screen起動直後の状態

これだけでも ssh 等でのリモート接続作業における不意な切断への対策や、動作に時間を要するコマンドをサーバ上で実行してデスクトップ端末はシャットダウンして帰宅できるなどのメリットを享受できますが、日常的な作業では複数のウィンドウを生成して領域を分割して使用する場合がほとんどだと思います。領域を分割した状態

そしてある程度 screen に慣れてくると、稼働監視コマンドを表示しつつ複数のホストへリモート接続して作業するなど、気がつくと一つの領域に収まりきらない数のウィンドウを作成するようになります。表示するウィンドウは select で自由に切り替えることができますが、どのウィンドウを端末の画面(=領域)に表示しようかという問題に悩まされます。 領域を複数分割した状態 しかしもっと悩ましいのは、そうやっていろいろ考えて分割・リサイズしたその領域は screen セッションにアタッチしている現在の端末に限られており、再度アタッチするとそれら領域の情報は無かったことになってしまうことです。一時的に :only で分割を解除して一つのウィンドウのみで作業したい場合にも同じことが言えます。

そんな悩みを解決してくれるのがレイアウトです。レイアウトには領域の分割状態や表示しているウィンドウ等の情報が保存されるので、複数のレイアウトを用途に応じて切り替えて使用することができます。レイアウトの情報はセッションに保存され、デフォルトでは再度セッションにアタッチした時は最後に表示していたレイアウトが表示されます。マルチディスプレイモード(複数の端末から同じセッションにアタッチscreen -x)でそれぞれ異なるレイアウトを表示することもできます。 レイアウトの概念

レイアウトの操作は layout サブコマンドを使用します。基本的な操作は window に対するものと似ています。デフォルトでは何もマッピングされていませんので、通常は使いやすいキーに bind して使う事になると思います。

  • :layout new [n] [title]
  • :layout remove [n|title]
  • :layout {next|prev}
  • :layout select [n|title]
  • :layout show
  • :layout title [title]
  • :layout number [n]
  • :layout attach [title|:last]
  • :layout save {n|title}
  • :layout autosave [on|off]
  • :layout dump [filename]
上から順番に。

layout new [n] [title]

n で番号、title で名前を指定してレイアウトを作成します。引数の指定がない場合は 0 始まりの番号で layout という名前のレイアウトが作成されます。いまのところレイアウト番号の数値には 0〜9 の値しか入力できず、作成できるレイアウト数の上限は 10 のようです。

layout remove [n|title]
レイアウトの番号または名前を指定してレイアウトを削除します。引数の指定がない場合は現在のレイアウトが削除されます。
layout {next|prev}

現在のレイアウトの次/前のレイアウトに切り替えます。おそらくリリース時に変更されると思いますが、ここでいう次/前はレイアウト番号の数値順ではなく、レイアウトを生成した順のようです。番号を指定してレイアウトを生成した場合やレイアウト番号を変更している場合は注意が必要です。3つ以上のレイアウトを切り替える場合には次に説明する layout select を使う方がストレスが溜まりません。

layout select [n|title]

レイアウトの番号または名前を指定して他のレイアウトに切り替えます。引数の指定がない場合は入力プロンプトが表示されます。

layout show

レイアウトの一覧をメッセージ行に表示します。windows と同じように現在のレイアウトには * が付きます。 メッセージ行に表示されるレイアウト一覧

layout title [title]

レイアウトの名前を title に変更します。引数の指定がない場合は現在のレイアウトの番号と名前がメッセージ行に表示されます。

layout number [n]

レイアウトの番号を n に変更します。引数の指定がない場合は現在のレイアウトの番号と名前がメッセージ行に表示されます。

layout attach [title|:last]

セッションにアタッチした際に表示するレイアウトを設定します。引数の指定がない場合は現在の設定がメッセージ行に表示されます。デフォルトは最後に表示したレイアウト(:last)です。

layout save {n|title}

レイアウトの番号または名前を指定してレイアウトを保存します。デフォルトでは次に説明する layout autosave が有効になっているのであまり使用することはないと思います。

layout autosave [on|off]

レイアウトの自動保存の設定を変更します。引数の指定がない場合は現在の自動保存の設定がメッセージ行に表示されます。デフォルトは自動保存が有効(on)です。off にできなくてもいいような気がします。

layout dump [filename]

現在のレイアウトの領域分割情報を filename で指定したファイルに出力します。引数の指定がない場合は layout-dump という名前のファイルに出力されます。いまのところ領域をどのように分割しているかという情報(split, split -v)しか出力されません。このファイルだけで領域のサイズや表示していたウィンドウまでを含めた設定が復元ができることを期待してはいけません。参考程度と考えておいた方が良さそうです。

開発版で実装されている機能とはいえ縦分割に比べると情報が少ないですが、レイアウトは GNU Screen において重要な機能のひとつだと言えます。レイアウトを用途に応じて切り替えることで、作業の効率がますます上がること受け合いです。

ちなみに、私は監視や特定の作業のためにこのように分割したレイアウトを長いこと使用していました。これとウィンドウ1つ、2つだけのレイアウトがあればだいたい事足ります。2つある作業端末のうち、一方で監視レイアウトを表示させて他方では同じセッションの作業レイアウトで操作をする、という使い方です。

実際の監視に使用していたレイアウト特定の作業で使用していたレイアウト

レイアウトのイメージ図を作成するにあたり、絵心のない私は以下のページで使用されている図を参考にさせていただきました。

ウィンドウグループ (window groups)

ウィンドウグループ名前のとおり複数のウィンドウをグループとしてまとめる機能です。グループごとにウィンドウが管理されます。nextprev などのコマンドや hardstatus などで使う書式(%w)が対象とするウィンドウは同一グループ内のウィンドウに制限されます。(右図はグループとウィンドウをいくつか作成したあとの状態と、同じセッションで一部のグループに移動した状態を windowlist で表示したもの)

ウィンドウグループを使用するには、まず //group オプションをつけてウィンドウを生成します。そのウィンドウがウィンドウグループとなり他のウィンドウのコンテナになります。

screen [-opts] [n] [cmd [args] | //group]
ウィンドウグループを生成した直後はそのグループの windowlist が表示されます。このあとに生成するウィンドウは基本的に全てこのグループに属することになります。

group [grouptitle]
既存のウインドウをグループに属させるには、対象とするウィンドウで group コマンドを実行します。引数で指定したグループに属するようになります。引数の grouptitle に存在しないグループ名を指定するとグループから除外されます。引数を指定しない場合はそのウィンドウが現在属しているグループ名がメッセージ行に表示されます。なお、ウィンドウグループを kill すると配下のウィンドウは無所属になります。

ウィンドウグループそれ自身もウィンドウですので、グループを作成した数だけ通常作業で使用できるウィンドウの数は減ります。わずかな数のウィンドウしか使用しない場合はウィンドウ操作が煩雑になるだけなのでグループを作成する必要はないと思います。しかし使用するウインドウが多数ある場合、windowlist における見通しがかなり良くなります。私は数十あるウィンドウをウィンドウ番号の十の位でカテゴリ分けしていますが、そのカテゴリを視覚化するという目的でウィンドウグループを使用しています。

マウス操作のサポート (mouse-tracking)

GNU Screen でマウス操作・・・だと・・・!?な… 何を言っているのか (ry

そうです。経緯は分かりませんがいつの間にかマウスでいくつかの操作ができるようになっています。

  • マウスクリックによるフォーカスする領域の指定
  • マウスクリックによるコピーモードでの始点・終点の指定
  • マウスクリックによるウィンドウリストでの選択(※決定ではない)
mouse-tracking はデフォルトでは有効になっていませんので、使用する場合は defmousetrack {on|off} で領域全体に対して有効にしておくか、使用したい領域を mousetrack [on|off] で有効にする必要があります。マウスによる操作を必要としないことが GNU Screen 使用目的の一つだと思っていましたので、この機能には驚きました。でも私は使わないと思います。

コマンドメッセージの抑止 (suppress message)

screen で実行するコマンドの接頭辞に @ (または-)をつけることで、コマンド実行後にメッセージ行に表示されるメッセージ、エラーメッセージを抑止できるようになりました。ただしメッセージ行に表示することが目的のコマンド(windowsなど)は対象外です。

たとえば、:kill コマンドでは実行後に次のようなメッセージが表示されますが、:@kill とすると表示されなくなります。

You destroy poor window 10 (zsh).

外部からのコマンド問合せ (remote query)

いくつかの screen コマンドの出力をメッセージ行ではなく標準出力に出力できるようになりました。

  • echo
  • info
  • lastmsg
  • number
  • select
  • time
  • title
  • windows
これにより外部プロセスで出力メッセージを利用できます。
$ screen -S sessionname -Q windows | perl -ne 'printf "%4s[%2d] %s\n", $2, $1, $3 while /(\d+)(\S+)? (.+?)(  |$)/g'
   -[ 0] top:ovs
    [ 1] top:debian
    [ 2] top:oel
    [ 3] top:osx
    [ 4] info screen
   *[ 5] vim
具体的な利用法はこのページが参考になります。

ウィンドウ番号の相対指定 (change the window's number by the relative amount)

ウィンドウ番号を変更する際に入力する数値の前に +- を与えることで絶対番号ではなく相対番号として指定できるようになりました。

number [[+|-]n]
地味な変更ですがありがたいです。windowlist の進化に一役買っています。

最大ウィンドウ数の変更 (increase the number of maximum windows)

パッケージとして配布されている screen では、一つのセッションで生成できるウィンドウ数の上限は定数 MAXWIN で 40 と決められており、また :maxwin [num] では現在より少ない値しか指定できませんでした。4.1.0 ではこの MAXWIN の値が 100 に変更され、現在より大きな値を指定できるようになりました。

ただしここで指定する数値は内部でのウィンドウ管理に使用する配列の初期値になると思われるので、ウィンドウを生成する前しか指定できません。それにデフォルトでこの数値は 100 になっているようですので、はたしてこのコマンドは必要なんだろうかと疑問に思います。でも最大ウィンドウ数がデフォルトで 100 まで広がったのは嬉しい変更です。以前は上限を変更するためだけにソースをコンパイルしていましたので。。。(→screenで40より大きな番号を設定する方法)

イベント発生ウィンドウの装飾設定 (change text attributes in caption for flagged windows)

いままでは :sorendition [attr [color]] コマンドでメッセージ行の書式(文字スタイルや色)を変更できましたが、それと同じようにしてイベント(bellmonitorsilence)が発生した際に captionhardstatus に表示するウィンドウの書式を変更できるようになりました。また、それにあわせて sorendition コマンドは非推奨となり、このコマンドに統合されています。(第一引数で so を指定)

rendition { bell | monitor | silence | so } attr [color]

設定とその表示例は次のとおり。ここでは5つウィンドウを作成して各イベントを発生させ、左右に分割した領域の左に windowlist、右に .screenrc の装飾に関わるを部分を表示している状態です。属性や色の定義については screen(1) の STRING ESCAPES を参照してください。イベント発生ウィンドウの装飾設定の例

設定で使用可能な変数/書式の追加 (support some variables during screenrc)

設定で使用可能な変数や書式が追加されました。

  • $PID screenのプロセスID
  • $PWD screenの作業ディレクトリ
  • $STY セッションの名前
  • ファイルパスにおけるチルダ展開のサポート
  • C言語風のエスケープ文字("\n", "\r", "\t")のサポート(stuff コマンド等で使用)
  • caption, hardstatusで指定できるもの
    • %p バックエンド screen のプロセスID
    • %+p フロントエンド screen のプロセスID
    • %S セッションの名前
  • captionで指定できるもの
    • %P コピーモードかどうかを判定する条件式(%Fのように使う)
設定とその表示例は次のとおり。ここでは2つウィンドウを作成して、上下に分割した領域の上では find コマンドを実行したあとにコピーモードでさかのぼっている状態、下は .screenrc の一部を表示している状態です。$変数は screen を起動してセッションを生成したときの値であるため、chdirsessionname などで変更した値ではないことに注意が必要です。 使用可能な変数/書式の例 今回の変更の中では %P でウィンドウがコピーモードかどうかを視覚的に判断できるようになったのが便利です。今のところレイアウトやグループに関連する値は無いので、正式リリース時にはサポートされることを期待します。

ウィンドウリスト/画面リストの拡張 (revamp the window/display list)

windowlist で行える操作が増えました。

  • m 一覧の並びをウィンドウ番号順・MRUリスト順とトグル切り替え
  • / ウィンドウの名前で検索(検索後、n で順方向、N で逆方向検索)
  • , 選択しているウィンドウと一つ上のウィンドウのウィンドウ番号を交換
  • . 選択しているウィンドウと一つ下のウィンドウのウィンドウ番号を交換
  • K 選択しているウィンドウをkill
  • ウィンドウグループ関連
    • g グループ内ウィンドウの表示・非表示をトグル切り替え
    • a (一番上のグループの場合)すべてのグループを展開して表示(それ以外)一つ上のグループの一覧を表示
    • Ctrl-H, BackSpace 一つ上のグループの一覧を表示
displays は端末の表示だけではなく、windowlist と同じように一覧上で操作ができるようになりました。
  • k, Ctrl-P, Up 一行上を選択
  • j, Ctrl-N, Down 一行下を選択
  • Ctrl-A, Home 先頭行を選択
  • Ctrl-E, End 最終行を選択
  • Ctrl-U, Ctrl-D 画面を半ページ上/下にスクロール
  • Ctrl-B, Ctrl-F 画面を一ページ上/下にスクロール
  • Space 一覧を更新(して自分の端末を選択)
  • d 選択している端末をdetach
  • D 選択している端末をpow_detach

256色サポート (256-color support)

  • 同梱の terminfo が256色対応しました
  • caption, hardstatus で使用可能な色が16色から256色に増えました

コマンド行の強化 (strengthening of command-input)

  • 実行履歴は一つ前までしか遡れませんでしたが、その制限が無くなりました
  • TAB キーによる補完が行えるようになりました
  • いくつかの readline 風なキーバインド(^W ^D ^P ^N)が使えるようになりました

コピーモードの検索機能強化 (adds some keys used to search in copy-mode)

コピーモードで検索に使用できるキーが増えました。

  • viライクな f F t T ; , による検索
  • Nによる逆方向検索

Scripting support

ChangeLog をよく見ると、気になる一文が in-progress としてあります。これが実装されるとまたスゴイことができそうです。

In-Progress:
* Scripting support (thanks to Google Summer of Code 2009 project by Rui Guo)

まとめ

正式版のリリースがいつになるのか分かりませんが、開発トランクではこのように数々のアツい機能が既に実装されていることがおわかりいただけたかと思います。GNU Screen(の開発)は終わった、という話を聞いたり、Google Insights などを見るとたしかに人気に陰りはあるようですが、こうして 4.1.0 での変更点をみると GNU Screen はまだまだ第一線で使うに充分足る、多少苦労してでも覚える価値のある time saving tool であると言えます。ネット上には開発版の導入方法は溢れています。みなさんも普段の CUI 作業をより一層効率化すべく開発版の GNU Screen を使ってみませんか?

私はどうしても譲れない機能のため、いくつかのパッチを当てたものを使用しています。他にも少し不満な点がありますので、今後はそれらの情報とビルド方法、開発版とともに使用している設定ファイルについてまとめていこうと思います。

それでは今年もよい GNU Screen ライフを!

2011/01/10更新 縦分割に領域についての説明を追加し、リサイズの説明を修正しました。ウィンドウグループ、装飾設定について書き直しました。変換により滲んでいたJPGファイルをPNGファイルに変更しました。

2011/01/12更新 実際に使用していたレイアウトのスクリーンショットを追加しました。

1 件のコメント:

  1. Your articles about Screen are great. They really deserve to be read by people. I am lucky I pasted it into google translator.

    返信削除