rcmdnk's blog
Last update

tmux 2: Productive Mouse-Free Development

ターミナルマルチプレクサとして GNU Screen を普段使っていますが、 tmux の方が活発に開発されてる様に見えたり 乗り移ってく人も沢山居るみたいなので気になって何度か試してみましたが、 イマイチ違いを吸収出来ずにScreenに戻ってきてました。

無理に移行する理由もそれ程無いですが、また試してみたので 取り敢えず違いなどのメモ。

設定ファイル

  screen tmux
ファイル名 ~/.screenrc ~/.tmux.conf

共にコメントは#から右がコメントになります。

現在の設定ファイル:

.screenrc

.tmux.conf

Prefix (Escape)

  screen tmux
デフォルトキー Ctrl-a Ctrl-b

共にデフォルトはコマンドラインで良く使うキーなので変更必須。 (screenの方は単にアルファベットの最初のキーだからaなのか、左端で押しやすいからなのか? まだ分かる気がしますが、tmuxの方は単にscreenとは違うもの、と言う意味でbなのか? いずれにしろ何方も何故それにしたか微妙。)

変更方法(Ctrl-qへ):

screen:

# Escape
escape ^Qq

tmux:

# Prefix
set-option -g prefix C-q
unbind-key C-b
bind-key C-q send-prefix

以下、Prefixの入力はPrefixと書いて行きます。

コマンドモード

共にPrefix :でコマンドモードに入れる。 以下、(:<command>)と書いてある物はコマンドモードでの入力の意味です。

キー設定一覧

  screen tmux
Help Prefix ?/(:help) Prefix ?/(:list-keys)

共にPrefix ?で一覧が見れます。

デタッチ/アタッチ

  screen tmux
セッション一覧表示 $ screen -ls $ tmux ls
アタッチ $ screen -r [<session number>] $ tmux attach-session [-t <session number>]
デタッチ Prefix d/(:detach) Prefix d/(:detach-client)

tmuxの方は引数をサブコマンドみたいに使います。 サブコマンド系はそれぞれ短縮されたaliasが用意されてますが (attach/detach等)、aliasでなくても短縮してそれが他と被って無ければ使えます。 例えばattach-sessionの場合は、aで始まるコマンドが他にないので tmux aだけでもtmux attach-sessionと同意になります。 detach-clientだと、他にdelete-clientなどがあるので detまで入れると認識してくれます。

なので、attachdetachではaliasそのものは実は意味ない感じですが、 上でも使ってるlsなんかはlist-sessionのaliasです。

また、screenの場合は-rでは既に接続されているセッションには接続出来ません。 -xを使うと既に接続してるセッションへもマルチ接続が可能です。 選べる複数のセッションがある場合にはセッション番号を指定してあげないといけません。

一方、tmuxの方はそれらの区別は無く、接続されてるものでもattach-sessionで接続出来ます。 この際、セッション番号を指定しないと、

  • まず接続されてないセッションの中から最後にデタッチされたセッション
  • 全て接続中なら最後にアタッチされたセッション

の順で探して接続します。

キーバインド

  screen tmux
基本バインド bind <key> <comamnd> bind-key <key> <command>
Ctrlの記述 ^a等^を使う C-a等C-を使う(^でも可)
コピーモードの設定 bindkey -m <key> <comamnd> bind-key -t vi-copy <key> <command>
シェルコマンド bind <key> ‘exec /bin/sh -c “<shell command>” bind-key <key> run-shell “<shell command>”
複数コマンド bind <key> eval ‘<command1>’ ‘<command2>‘… bind-key <key> ‘<command1>’ \; ‘<command2>’ \;…
submode的な bind <key> ‘command -c sub’、の後bind -c sub <key> <command> bind-key -r <key> <command>

追記: 2015/01/06

tmuxのヘルプを読み直したらCtrlはscreenの様に^aでも出来る 事に気づいたので追記。

追記ここまで

tmuxの方はbindbind-keyのalias設定されてるので bindでもOK。 また、run-shellrunがalias設定されています。

コピーモードの設定はtmuxではvi/emacsモードがあり、上のはviモードの設定。 emacsモードの方を変更したい場合は-t emacs-copyで。

複数のコマンドを指定したいときは、screenではevalを使った後、 コマンド毎にクォートして羅列していきます。 一方、tmuxの方はコマンドの間に;をエスケープした\;を入れてつなげていきます。

また、tmuxではconfirm-beforeというコマンドが使えて

bind-key x confirm-before -p "kill-pane #P? (y/n)" kill-pane

の様に通常コマンドの前に書くと、 実行時に実際に実行する前に確認してくれます。 これもscreenに無いtmuxの賢い機能。

submode的な、と書いたのはキー入力単体でコマンドを送れる様なモードのことです。 screenとtmuxでは基本的には違うものですが、 screenではcommand classを設定することでキー入力後にさらに特殊なキー入力待ちを することが出来、これを再帰的に行うことでsubmode的な動きが出来ます。 一方、tmuxでは-rを指定することで一度他のコマンドを送った後に2回目以降 Prefix無しでキーを送れるようになります。

例えば複数に分けた領域の1つを連続的に広げたり狭めたりしたいとき、 screenでは

# Resize window
bind e eval 'command -c resize' 'echo "Resize window"'
bind ^e eval 'command -c resize' 'echo "Resize window"'
bind -c resize h eval 'command -c resize' 'resize -h -1'
bind -c resize l eval 'command -c resize' 'resize -h +1'
bind -c resize j eval 'command -c resize' 'resize -v +1'
bind -c resize k eval 'command -c resize' 'resize -v -1'
bind -c resize ^h eval 'command -c resize' 'resize -h -1'
bind -c resize ^l eval 'command -c resize' 'resize -h +1'
bind -c resize ^j eval 'command -c resize' 'resize -v +1'
bind -c resize ^k eval 'command -c resize' 'resize -v -1'

みたいにするとPrefix eを押した後、 hlで左右に連続的に広げたり狭めたり出来ます。

一方、tmuxで同じような事をしたい場合は

# Resize pane
bind-key -r C-y resize-pane -L
bind-key -r C-u resize-pane -D
bind-key -r C-i resize-pane -U
bind-key -r C-o resize-pane -R

の様にするとPrefix Ctrl-yとした後、 Ctl-yCtl-oで連続的に 幅を広げたり狭めたり出来ます。

tmuxの方が簡単に設定できますが、 screenのcommand classは理解できると色々複雑な事が出来るので 一長一短な感じ。

コピーモード/履歴スクロールバック

screenではコピーモードは基本、viのキーバインドですが 1、 tmuxの方はemacsモードとviモードが選択出来ます。

デフォルトはemacsですがVISUALまたはEDITORという環境変数が viを含む値(i.e. vim)だとviモードになります。

または

set-window-option -g mode-keys vi

と設定しておくとviモードになります。 (emacsモードにしたいならviの代わりにemacs)

以下はviモードの話。

  screen tmux
コピーモード開始 Prefix [ Prefix [
選択開始 Space Space
選択完了 Space Enter
行選択 Spaceの代わりにyで選択開始 Spaceの代わりにV(:select-line)で選択開始
矩形選択 cで左端指定、Cで右端指定 選択開始後、v(:rectangle-toggle)で矩形選択へ
履歴保存行 defscrollback <n lines> (default 100) set-option -g history-limit <n lines> (default 2000)
search /?nN like vim /?nN like vim
検索時にwarpする defaultでoff set-option -g wrap-search [on&rvbar;off] (default on)

screenに慣れてるとtmuxでもコピーの完了時にSpace を押してしまってコピーできずにちょっと戸惑います。 まあ、そこは慣れですね。

特にscreenの矩形選択が分かり辛いので、 それに対するtmuxの方法は大分良い感じです。

tmuxのコピーモード時のキー設定は : list-keys -t vi-copyで見ることが出来ます。

また、Prefix Ctrl-[ でもコピーモードに入れる様なキーバインドを設定したいとき、 Ctrl-[ESCと同値なので、 tmuxの場合にちょっと注意が必要です。

tmuxではtmux自体でエスケープシーケンスを 解析する様な構造になってるらしく、 escape-timeという設定項目があります。

この設定はデフォルト500でms単位でエスケープシーケンスを待つ時間の設定になっています。 コピーモードに入りたいときに Prefix Ctrl-[で入ろうとすると、 この時間の分だけ一時的に待つのでちょっとタイムラグが有ります。

なので、これを

set-option -g escape-time 1

の様に最小値にしておきます。

もし必要なキー入力がある場合には、必要な場合、メタキー+keyの形で入力出来るように 設定しておきます。

メタキー/ESCについて: iTermでそれらのキーを送る設定も

screenではクリップボードは通常1つしか管理できませんが、 tmuxではデフォルトで複数クリップボードが管理できて過去のクリップボードを 再利用することが出来ます。

ただ、screenでもmulti_clipboard を使えば複数クリップボードを管理できます。

追記: 2015/01/04

両者とも、環境に応じてスクロールバックして戻れる行数を指定してあげることが出来ます。 特に、screenの方はデフォルトが100行だけなので普通に使うなら増やしておかないと不便です。

リソースが少ないサーバーとかで絶対負荷を掛けたくない、という場合を除いて 1万行くらいにしておいてもメモリの問題等は無いので大体それくらいに。

それから、screenの方はコピーモード時に検索でnで進んでいくと、 一番下まで行くと止まりますが、 tmuxの方はwrapモードがデフォルトで一番下まで行くと一番上の物に戻ります。

screenの方は設定変更はありませんが、tmuxではこれをwrap-search というオプションでon/offしてあげる事ができます。

また、screenの方は1万行、と設定していると最初から1万行確保される様な形になっていて、 開いたばかりのWindowでも空白行が上に続いていて、 ggとかで一番上まで行くとずーっと空白行が続く空間に飛ばされます。

一方tmuxの方は実際に始まった所が最初になってるので、この点は tmuxの方が良い点です。

追記ここまで

Session/Layout/Window/Pane

screenとtmuxの違いの最大の点はWindow/Paneの意味の違いです。

screenではそれぞれのシェルが実行されてる領域はWindowと呼ばれます。 Windowはセッション全体で一括で管理されています。 (一応、Window GroupというWindowをグループ化して管理する機能もあります 2。) Windowは画面上に表示せずに隠しておくことも可能で、 また、分割された複数の領域に同時に表示することも可能です。

screensketch

一方で、tmuxのWindowは表示される画面の事を言います。 各領域はPaneと呼ばれます。 Paneは各Windowに属していて、必ず何れかのWindowの中に表示される 必要があり、また、screenと違い同時に2つ表示する事は出来ません。

tmuxsketch

この違いから、tmuxの場合は、特に分割して使う場合、 基本的に一度Windowを作ったら 表示を変更したりせずにそのまま使う、と言うのが通常の使用方法になると思います。

screenの使い方が、割りとWindowを次々と入れ替えながら使ったりするので、 この違いがtmuxに移行が中々進まない最大の理由だったりします。 (逆にtmuxの感覚に最初に慣れてればscreenの感覚は足りない感じがするのでしょうが)

Layoutに関してはscreenの場合は自分で用意する必要がありますが 3、 tmuxに関しては予め幾つかレイアウトが用意されていて Prefix-Spaceでレイアウトを変更することが出来ます。

screenのレイアウトはWindowの表示位置や分割数もきちんと決まったものだったりしますが、 tmuxの場合はWindow内のPaneの数によって良しなに設定してくれます。

even-horizontalというレイアウトは等間隔で横方向に並べ、 even-verticalというレイアウトは等間隔で縦方向へ、 またtiledという全てのPaneをなるべく同じような大きさに設定してくれる物もあります。

レイアウトに関してはtmuxの機能は結構優れてると思います。

また、tmuxで 一時的に一つだけ全体表示したい、みたいな事をしたいときに、 :break-paneというコマンドで現在のPaneだけのWindowを別途作って 表示、みたいなことも出来ますがこの場合は元に戻す時には 元のWindowに戻って独立させたPaneを移動させて、みたいなことが必要になってしまいます。

コレに変わって、tmux1.8以降では、

:resize-pane -Z

というコマンドが用意されています。(デフォルトでPrefix zにバインドされてます。) これをすると、一時的に現在のPaneだけの表示になります。 もう一度Prefix zなどすれば元に戻ります。

最後にSessionに関してですが、 基本的には同じ様なものですが、 tmuxの方ではSessionの上にServerが動いていて、 全てのSessionServerに管理されています。 このため、tmuxの方では1つのSessionの中からchoose-session等で 直接他のSessionに移ることも可能です。

それからtmuxの方にはClientという概念もあって、 Sessionに接続している端末名(/dev/ttys001等)が管理されています。 これを使って端末ごとにdetachさせたりすることも可能です。

split

ちょっと前まではscreenの方はパッチを宛てないと縦分割出来ないような状態だったので それもtmuxの便利な点の1つでしたが 最新のものではtmuxもscreenも横分割も縦分割も出来るようになっています。

で、ここで少し混乱するのが、(vertical)分割と(horizontal)分割の定義が tmuxとscreenで逆なことです。

screenの方は縦分割(:split -v)は縦方向に線が入る様な分割、 tmuxの方は縦分割(:split-window -v)は縦方向に並べる様な分割。

Vimなんかだと:vsplitはscreenの様に縦方向に線が入って横に並べる様な表示です。

screenではPrefix S等を横分割、 Prefix V等を縦分割にしていましたが、 この動きと合わせるためにはtmuxでは逆に Prefix S等を縦分割(:split-window -v)、 Prefix V等を横分割(:split-window -h)にする必要があります。

全Paneに同時入力

tmuxを使いたい理由になる機能の1つ。

:set-window-option synchronize-panes on

をすると現在のWindowにある全てのPaneに対して同時に同じ キーを送る様になります。

複雑な作業を同時に行うのはあれですが、 サーバー管理等で複数端末にshutdownコマンドなど簡単なコマンドを送りたいとき なんかは便利です。

:set-window-option synchronize-panes off

とすると解除されます。

swap-paneの問題

tmuxでPaneを他のWindowへ送ったり移動させたりする swap-paneというコマンドがあるのですが、 これが現行の安定バージョンの1.9aの場合、 [lost server]と出て落ちてしまう事があります。

スワップしようとするPaneがある2つWindowの何方かが Paneが1つしかない場合にこの現象が起こる様。

開発版の方の2.0を入れるとこの現象は起こらないので、 swap-paneを多用する場合は2.0が必須です。

開発版はMacだとHomebrewで

$ brew install tmux --HEAD

で入れる事が出来ます。

Linuxなどだと直接Gitレポジトリから取ってきてコンパイルする必要がありますが、 automake等、全てローカルに自分でコンパイルして入れてる場合、 少し面倒があったので注意が必要です。

ローカルインストールしたautomakeを使って./autogen.shから./configureする際のトラブル解決

Status表示

screenの方はこちら参照。

GNU screenのcaptionとhardstatusの整理

tmuxの方は各Pane毎のcaptionの様な物は無く、 全体のstatusラインだけがあります。 また、screenではコマンド表示用のラインは別途一行用意されますが、 tmuxではコマンド/結果の表示はstatusライン上になります。

tmuxのstatusラインでは、真ん中にWindow情報、 さらに左側と右側に別途情報が載せられる様に設定出来ます。

set-window-option -g window-status-format "window info"
set-window-option -g window-status-current-format "current window info"
set-option -g status-left "left info"
set-option -g status-right "right info"

の様な設定。Window情報は現在のWindowとその他で表示を変えられます。

Window情報はPaneの新規作成等、Windowの状況が変わるたびにアップデートされます。

一方、left/rightの方はstatus-left-length/status-right-length で指定された秒数毎にアップデートされます。(デフォルトは15秒) left/rightの中では#()を使って通常のシェルコマンド等を指定することも出来、 lengthで指定された間隔毎にコマンドを実行して結果を表示できます。 これによってかなり自由度が高い表示が可能になっています。 (Window情報では#()形式でのコマンド指定は出来ません。)

ステータス表示ではプロンプト表示のPS1への指定 の様に#hで短縮ホスト名等を指定することも可能です。 また、tmux内の情報を#{window_panes}の様に持ってくる事が出来る物もあります。 (詳しくはman tmuxFORMATSの項目で。)

ステータスラインの色指定は、全体を指定したい場合は

set-option -g status-style "bg=colour236,fg=black,bold,underscore"

status-styleを設定します。 fg/bg両方指定したい場合は,でつなげます。

left/right領域を別に設定したい場合には status-left-style/status-right-styleという設定項目もあります。

ここで、色指定には black, red, green, yellow, blue, magenta, cyan, white の8種類か、 colourN(N=0-255)という形での色指定4、 または#ffffffという16進法の指定も可能です。 (ただし、この場合全ての色が可能なわけでなく、256色使える端末なら 指定色に一番近い色が表示されます。)

色指定の所で注意なのがcolour255みたいな指定をするときに、 アメリカ英語のcolorではなく、イギリス英語のcolourの綴りになってる所。

tmuxのヘルプの中も通常のカラー、というところは全てcolourになってます。 プログラムしてる中でcolourを使ってるのは殆ど見たこと無いので なんとなしに書くと間違えて色が変わらなくて戸惑います。

また、printfを使ったりPS1の値などでWindowのタイトルなどを変更できますが 以下の様な値で変更が出来ます。

  screen tmux
\ek~\e\134 Window title Window Name
\e]2;~\a - Pane title

PS1とPROMPT_COMMAND, GNU screenでの活用も

.bashrcなどでの判断方法

.bashrcなどでscreenやtmuxの中かどうかで設定を変えたい場合、 基本、両方共TERMの値がscreenになっているのでそれを使います。

1
2
3
4
5
6
7
if [ "$TERM" = screen ]; then
  # settings for screen/tmux
  ...
else
  # settings for other than screen/tmux
  ...
fi

また、screenとtmuxを区別したい場合には tmuxの場合にはTMUXという環境変数が設定されるので

1
2
3
4
5
6
7
8
9
if [ "$TERM" = screen ]; then
  if [ "$TMUX" = "" ]; then
    # settings for screen
    ...
  else
    # settings for tmux
    ...
  fi
fi

みたいにすると判断できます。 (もしくはscreenの場合にはTERMCAPの値が SC|screen|VT 100/ANSI X3.64 virtual terminal:... みたいな値になっています。 特に指定して無ければtmuxではこの値は指定されません。)

違いが理解できたら

上の違いを踏まえた上でtmuxをscreenの様に使えるようにカスタマイズしてみます。 (ならscreenを使え、というのはなしでsweat_smile)

tmuxのPaneの扱いをGNU screenのWindowの取り扱いになるべく近づけてみる

Sponsored Links
Sponsored Links

« ローカルインストールしたautomakeを使って./autogen.shから./configureする際のトラブル解決 tmuxのPaneの扱いをGNU screenのWindowの取り扱いになるべく近づけてみる »

}