HOME

tmux メモ

20170328

tmux をいいかげんに使っていたが、ちょっとずつストレスがたまってきたので、ごく素朴にプロセス・ツリーや制御端末を観察をしながら、メモを作った。ウソ書いてたら、ごめんなさい。

最初のメモ

コマンドを実際に打鍵するとき

tmux に対してコマンドを打つ場合、シェルに対して tmux commandname のようにするか、tmux のクライアントが支配している画面に対して C-b : を打ち、画面最終行に : というプロンプトが出たらそれに続けて commandname を打鍵する。こうした打鍵は C-b に続けて : 以外の一文字を打つという簡略な方法が用意されていることがある。セッションやウィンドウなどを対象とするコマンドには、コマンドが打たれたときの現在のセッション、現在のウィンドウを暗黙のうちに対象とするものが多い。

(以下、こうした commandname を、(シェルに打ち込むときの書き方で)「tmux commandname」と記すことにするが、これは C-b : に続けて commandname を打鍵するというやり方をしても同じである。)

セッションとプロセスグループの復習

探索に最低限必要なことだけ復習。

課-係-職員みたいな感じで、セッションの下にプロセスグループがあり、プロセスグループの下にプロセスがある。

課の名前(SID)は、課長の名前(セッションリーダーのPID)に等しい。係の名前(PGID)は、係長の名前(プロセスグループリーダーの PID)に等しい。

端末(TTY)は課(セッション)ごとに 1 台あるが、端末のない課(セッション)もある。一度に一つの係(プロセスグループ)しか端末を使えない。端末を使っている係(プロセスグループ)をフォアグラウンドにあると言う。TPGID は現在端末を使っている係の名前(フォアグラウンドにあるプロセスグループのID)のことである。

その他。パイプでつながったプロセスは同じプロセスグループに属する。シェルはプロセスグループを管理するとき、ジョブという言い方をする。

ps xj をしてみると、これらの情報が得られる。x は制御端末を持たないプロセスも表示し、j は、色々な情報も表示するオプション。

なお、ここで言ったセッションというのは、tmux 用語でいうセッションとは異なる。tmux は、ここでいうセッションをいくつか集めたものをセッションと呼んでいる。

探検開始

私のマシンで pstree と打ってみると、その大元には 1 つのプロセス systemd がある(いにしへはこゝに initd がゐた)。そこから延々とプロセスツリーを下って行けば、xterm というプロセスがあって、その下で bash のプロセスが動いている。(ふだんは mate-terminal を使っているけど、こいつはいくらウィンドウを開いても一つのプロセスなので、わかりやすいように xterm を用いた)。以下プロセス ID が長くてわかりにくいから、これを簡単にして (1) (2) (3) ……という番号に書き換えることにし、必要に応じてプロセス名のあとにくっつけて書き、同名の別プロセスと区別できるようにした。

                           制御端末はpts/1
                                  ↓
  systemd(1)---...---xterm(2)---bash(3)

この bash(3) に向けて、tty と打鍵すると、/dev/pts/1 という pty なファイルが報告される。これは擬似端末(正確にはそのスレイブ側)というやつで、bash(3) はこれがスクリーンやキーボードからなる本物の端末であると思い込んで暮らしているのだ。bash(3) の制御端末が /dev/pts/1 であると言うことができる。(以下 /dev/ のところ省略して書く)

さて、この bash(3) に向けて tmux と打鍵すると、画面のいちばん下の行に緑色の帯が現れる。pstree コマンドでプロセスツリーを確認すると、おっと、tmux という名前のプロセスが 2 つ立ち上がっているじゃないか。tmux(4) と tmux(5) だ。それに bash(6) というプロセスが新規に発生している。

                                 制御端末はpts/1
                                  ↓          ↓
  systemd(1)---...---xterm(2)---bash(3)---tmux(4)
     |
     +--- tmux(5)---bash(6)
                      ↑
              制御端末はpts/2

ここで緑帯画面(ターミナルという言葉が混乱を引き起こすといけないので、こういう言い方をしておく)から、echo $$ と打鍵してみると、6 が戻ってくる。つまり、この緑帯画面で動いているシェルは、もはや以前の bash(3) ではなく、新規に作られた bash(6) なのである。ためしに緑帯画面からこの bash(3) に向けて tty と打鍵してやると、pts/2 という返事である。

tmux を起動する前は、私の打鍵は pts/1 を通して bash(3) に渡っていたのだが、tmux を起動して、緑帯画面になってより後は、私の打鍵は pts/2 を通して bash(6) に渡るようになったというわけだ。

man tmux によると、tmux(4) をクライアント、tmux(5)をサーバとしてソケット通信が行われているということで、この 2 つの tmux プロセスが連携してこのトリックを実現しているということになる。このことを特に強調すると、次のように書き表すことができる。

       (サーバ側)    ソケット通信  (クライアント側)
    +--------------------------------------------+
    |                                            |
    +----> tmux(5)---bash(6)        tmux(4) <----+

さて、緑帯画面で vim を立ち上げると、プロセス・ツリーは以下のように変化した。

  systemd(1)---...---xterm(2)---bash(3)---tmux(4)
     |
     +---tmux(5)---bash(6)---vim(7)
                      ↑        ↑
                      制御端末はpts/2     

緑帯画面にいるのが bash(6) なのだから、当然といえば当然である。

なお vim(7) の制御端末は、bash(6) と同じで pts/2 になっている。ただ、bash(6) がバックグラウンドにあって、vim(7) がフォアグラウンドにあるから、緑帯画面を見ながら私が打ったキーの入力は、vim(7) のほうが戴くことになる。

ここで再びサーバ・クライアント関係がわかるように記してみると、次のような具合だ。

             (サーバ側)    ソケット通信  (クライアント側)
    +-----------------------------------------------------+
    |                                                     |
    +----> tmux(5)---bash(6)---vim(7)        tmux(4) <----+

じつは、これだけでも大したものだ。というのは、クライアント側の tmux(4) プロセスに事故があっても、サーバ側の tmux(5) プロセスが無事なら、vim(7) は無事なのだ。

だが、話はまだ複雑になっていく。

2 つ目のクライアント

xterm をもう一つ立ち上げ、彼のためにウィンドウ・マネージャが用意した新しい窓に向かって、再び tmux と打ち込んでみる。そうすると、この新たな窓の中に緑帯画面(その2)が出現する。プロセス・ツリーは次のようになった。赤字のところが、増えたプロセスである。

systemd(1)-+-...---xterm(2)---bash(3)---tmux(4)        ……… 緑帯画面(その1)
     |       |
     |       +-...---xterm(8)---bash(9)---tmux(10)    ……… 緑帯画面(その2)
     |
     +--- tmux(5)-+-bash(6)---vim(7)
                  |
                  +-bash(11)

新たに立ち上がったクライアント tmux(10) のために、サーバ tmux(5) は bash(11) を用意したのである。

緑帯画面(その2)で echo $$ をやってみると、11 だ。緑帯画面(その2)の奥で動いているのは、bash(11) というわけだ。最初に立ち上げたクライアント tmux(4) がキー入力を bash(6) に送るよう画策したように、いま立ち上げた tmux(10) は、キー入力を bash(11) に送るようにトリックを使っているのだ。で、この bash(11) の制御端末はどうなっているのだろう。

ps -l コマンドで各 bash プロセスの制御端末を調べてみると、次のようになっている。

                             ((pts/1))  ((pts/1))
systemd(1)-+-...---xterm(2)---bash(3)---tmux(4)
     |       |
     |       |                  ((pts/4))   ((pts/4))
     |       +-...---xterm(8)---bash(9)---tmux(10)
     |
     |            ((pts/2))  ((pts/2))
     +--- tmux(5)-+-bash(6)---vim(7)
                  |
                  |  ((pts/6))
                  +-bash(11)

サーバの tmux(5) は、tmux(10) のために bash(11) プロセスを作るとき、bash(11) のために新たに pts/6 という擬似端末を用意したのだ。そして、tmux(10) は、tmux(5) とソケット通信で打ち合わせをして、キー入力がこの pts/6 にいくよう仕向けたというわけである。

(pts/N といった擬似端末は、キー入力だけを扱うわけではないが、とりあえず一つの例として、以下ずっとキー入力を取り上げる)

ここまで起こった事件をまとめると、こうだ。「tmux(4),tmux(10) の各クライアントは、サーバたる tmux(5) と共謀し、それぞれ pts/2 と pts/6 を用いて、それぞれ bash(6) 以下のプロセスと bash(11) 以下のプロセスに、キー入力を届けるべく図ったものである。」

              サーバ側     (ソケット通信)  クライアント側
    +------------------------------------------------------+
    |                                                      |
    +----> tmux(5)-+-bash(6)---vim(7)        tmux(4)  <----+
                   +-bash(11)               tmux(10)  <----+

という具合だ。

ウィンドウ

さて、tmux にはプレフィックス・キーというものがあって、緑帯画面を表に持ってきた状態でこのキーを押すと、その後に続けたキー入力は tmux のクライアントに届く。こうして tmux クライアントに対してコマンドを使うと、色々なことができる。

さっそく tmux(6) がいる緑帯画面で、Ctrl-b c を打ってみると、vim が画面から消えて、シェルが入力を待っている画面に変わった。Ctrl-b n や Ctrl-b p で元の vim がいる画面切り替えられる。tmux のギョーカイ用語で、これを「新しいウィンドウを作った」と言う。ウィンドウマネージャが作る窓と区別するために、これをヰンドウと呼ぶことにする。緑帯画面その1にヰンドウ0とヰンドウ1ができたということである。

pstree でプロセス・ツリーを確認してみると

  systemd(1)-+-...---xterm(2)---bash(3)---tmux(4)
     |       |
     |       +-...---xterm(8)---bash(9)---tmux(10)
     |
     +--- tmux(5)-+-bash(6)---vim(7)
                  | 
                  +-bash(11)
                  | 
		  +-bash(12)
                         ↑
                     制御端末は pts/8

のようになっている。サーバ tmux(5) 配下に、出現したプロセス bash(12) が新入生である。一方、クライアント側の tmux(4) 周辺には何の変化も見えない。

ためしに、緑帯画面その1のヰンドウ1で echo $$ をやってみると、予想通り 12 が戻ってくる。また、tty を打ってみると pts/8 が得られる。もちろん、ps -l コマンドで bash(12) の制御端末を調べると pts/8 になっている。

tmux のクライアントでヰンドウを新規に作成すると、サーバ側の tmux プロセスの子として新たに bash プロセスが用意され、その bash プロセスが接続しているのは、新規に用意された擬似端末なのだ。

サーバ・クライアントの関係は、次のように記すことができる。

              サーバ側     (ソケット通信)  クライアント側
    +------------------------------------------------------+
    |                                                      |
    +----> tmux(5)-+-bash(6)---vim(7)        tmux(4)  <----+  緑帯画面1 ヰンドウ0
                   +-bash(12)                              |        ヰンドウ1
		   |                                       |
                   +-bash(11)                tmux(10) <----+  緑帯画面2

ペイン

さらに、tmux(10) を起動した緑帯画面その 2 で、Ctrl-b-" を打ってみる。緑帯画面その 2 が上下 2 つに分割された。これを tmux 用語では、ペインを新規に作成したという。プロセス・ツリーは、次のように変化した。

  systemd(1)-+-...---xterm(2)---bash(3)---tmux(4)
     |       |
     |       +-...---xterm(8)---bash(9)---tmux(10)
     |
     +--- tmux(5)-+-bash(6)---vim(7)
                  | 
                  +-bash(11)
		  |
		  +-bash(12)
		  |
		  +-bash(13)
                         ↑
                   制御端末は pts/9

プロセス・ツリーに起こっていることは、新規ヰンドウを作成したときと全く同じだ。サーバ側の tmux(5) 以下に新しく bash(13) プロセスが作成され、このプロセスは新規に用意された pts/9 擬似端末に接続している。どうやら、ヰンドウを作るのもペインを作るのも、プロセス・ツリー的には同じことなのだ。

これを書き換えると、次のようになる。

              サーバ側     (ソケット通信)  クライアント側
    +------------------------------------------------------+
    |                                                      |
    +----> tmux(5)-+-bash(6)---vim(7)        tmux(4)  <----+  緑帯画面1 ヰンドウ1
                   +-bash(12)                              |        ヰンドウ2
		   |                                       |
                   +-bash(11)                tmux(10) <----+  緑帯画面2 ペイン1
                   +-bash(13)                                           ペイン2

セッション、ウィンドウ、ペイン、クライアントの特定

さて、そろそろ tmux ギョーカイ用語を使って語らなければならないときになった。

セッション

上のプロセス・ツリーを見るとわかるように、サーバ・プロセス tmux(5) 以下には、bash(6),bash(12) 以下の塊と、bash(11),bash(13) 以下の塊があり、それぞれ tmux(4) と tmux(10) というクライアント・プロセスと仲良しだ。この 2 つの派閥をそれぞれセッションと呼ぶ。(これは、至極大雑把で不明瞭で誤解を生む表現だが、bsh(6) と bash(12) が、そして bash(11) と bash(13) が同一セッションに属しているということを強調したかった。じつのところ、2 つ以上のクライアントを同一セッションに接続するということは可能である。しかし、こうしたとき、あるクライアントが bash(6)と仲良くしながら、bash(12) と仲良くしないということは不可能だ。クライアントはセッション単位でしかサーバにつながることはできないのである)

(同じ SID を持つプロセスをセッションというなら、tmux(5);bash(6),vim(7); bash(12); bash(11); bash(13); tmux(4); tmux(10) という 7 つのセッションがあるが、これは OS 用語(?)のセッションであって、tmux 用語では、これをセッションとは呼ばない。tmux にいうセッションというのは、OS にいうセッションがいくつか集まったもの、とでも言うべきか。以下セッションといったときには、tmux 用語のセッションである)

tmux のコマンドなんかを使うときに、これらのセッションを特定するには、いくつかの方法がある。まずは、セッション名だ。いずれかのターミナルから tmux list-sessions と打鍵すると、

0: 2 windows (created Thu Mar 30 12:21:44 2017) [80x23] (attached)
1: 1 windows (created Thu Mar 30 12:21:48 2017) [80x23] (attached)

のような出力が得られる。ここで行頭に出た 0 とか 1 とかいうものがセッション名である(セッションにはインデックスというものはないもよう)。これは数字であるとは限らない。われわれは最初にたんに tmux と打鍵するところから始めたのでこういうことになったが、これが tmux new -s test のようにしたのであればば、0 や 1 という数字の代わりに test という文字列が使われることになるのである。

このセッション名のほかに、セッション ID というものがある。tmux list-sessions -F '#{session_id}' のように打鍵すると

$0
$1

のような出力が得られるが、この $0 や $1 というのがセッションID である。セッション名が変更できる(rename-session というコマンドがある)のに対して、セッション ID は変更することができない。

ヰンドウ

われわれがヰンドウと呼んできたものは、セッション下位にあるカテゴリーだ。

セッションの下には少なくとも、ヰンドウが 1 つは存在する。

ヰンドウの特定方法には、
(1) 0から始まるインデックスを使う
(2) ID を使う
(3) 名前を使う

の 3 種類がある。(2) は他のセッションと重複しないので、単独で用いることができる。(1) を使う場合は、セッション名を : をはさんで前置して、mysession:0 のようにする。名前も同様で mysession:mywindow のようにする。名前を整数にした場合、名前よりインデックスが優先されると思うけど、試してない。

緑帯の中には、こうした情報が含まれている。たとえば、ステータスラインの左端のほうが

[a] 0:b- 1:c*

となっているならば、[a] はセッション名で、0:b- というのは、このセッションにおけるインデックスが 0 の b という名のウィンドウがあり、アクティブでない(- フラグ)。また、このセッションにおけるインデックス 1 の c という名のウィンドウがあり、アクティブである——ということを意味する。

一般性があるかどうかわからないが、私のところではヰンドウに明示的に名前をつけないと、その中で動いているプロセス名がヰンドウ名となり、そのプロセスが変わるごとにウィンドウ名が変更される(ただ、この変更がすぐにはステータスラインに反映されないことがある)。tmux rename-window で明示的にウィンドウに名前をつけた場合、これは固定される。

どういうヰンドウが存在するかを知るためには、セッション名を使って tmux list-windows -t 0 のようにするか、セッション ID を使って tmux list-windows -t '$0' のようにする(後者をクォートしているのは、シェルによって解釈されないため)ことができる。実際、tmux list-windows -t 0 として、tmux(4) プロセスに対応するセッション下にあるヰンドウ、つまり、緑帯画面その 1 中で見ることのできるヰンドウをリストしてみると

0: vi- (1 panes) [80x23] [layout ae5d,80x23,0,0,0] @0
1: bash* (1 panes) [80x23] [layout ae5f,80x23,0,0,2] @2 (active)

のように表示された。行頭の 0 と 1 とはヰンドウのインデックスであり、整数が割り当てられる。後続する vi とか bash とかいうのは、ウィンドウ名である(たまたまプロセス名が使われている)。rename-window というコマンドがあるし、tmux-new window -n hoge としてヰンドウを作成すれば、ヰンドウ名は hoge となる。ヰンドウ名の後にある - とか * とかいうフラグは、どのウィンドウがアクティブになっているかを示すものだ(* がついているのがアクティブ)。そして、行末にある @0 と @2 というのが、ヰンドウ ID だ。番号がとんでいるのは、@1 という ID を別のセッションが使っているからに他ならない。

ペイン

ペインはヰンドウのさらに下のカテゴリーである。

セッションが少なくとも 1 つのヰンドウを持つように、ヰンドウは少なくとも 1 つのペインを持つ。

ペインを特定するためには、
(1) ペインインデックス
(2) ペインID

の 2 つの方法がある。(2) は他のセッション、他のウィンドウと重ならないので、単独で用いることができる。(1) を使う場合、sessionname:windowname.0 のようにする。

どういうペインが存在するかを知るには、tmux list-panes -t 1:0 のようにする。この例は、セッション名 1 のセッション以下にあるウィンドウインデックス 0 のウィンドウ以下にあるペインを報告せよという意味だ。実際やってみると

0: [80x11] [history 0/2000, 0 bytes] %1 (active)
1: [80x11] [history 0/2000, 0 bytes] %3

のような報告が返ってきた。行頭がペインのインデックスである。行末にある %1 や %3 というのはペインの ID である。%2 がとばされているが、これは %2 が他のセッションに存在するので、重複しないようそうなっているのだ。

クライアント

セッション、ヰンドウ、ペインと登場人物を見てきたが、もう一人名前がついている人がいる。それはクライアントだ。tmux ではクライアントを特定するためには、そのクライアントが接続している pty の名前を用いることになっている。われわれの例では、それは pts/1 と pts/2 であった。

われわれは、今まで注意深くプロセスの制御端末になっている擬似端末を調べてきたから、pts/1 とか pts/2 とかがいったいどのクライアント・プロセスを表すのかを把握している。だが、普通 tmux を使う場合、そういうことは望めない。しかも、緑帯画面の中にあるシェルに対して tty コマンドを打って出てくる pty 名は、いま相手にしているクライアントの制御端末ではなくて、いま相手にしているペインと仲良くしている〈サーバプロセス直下に存在するシェル〉の制御端末名に過ぎない。

tmux list-clients コマンドを打ってみると、

/dev/pts/1: 0 [80x24 xterm] (utf8) 
/dev/pts/2: 1 [80x24 xterm] (utf8) 

のように出る。/dev/pts/1 や /dev/pts/2 がクライアント名であり、その後の 0 とか 1 とかいうのはセッション名である(コマンドに書くときに /dev/pts/N は pts/N と省略できる場合が多いもよう)。緑帯画面は、緑帯の最左端にセッション名が出ている。これらの情報を併わせると、現在自分の目の前にある緑帯画面を司どっているクライアント名を知ることができる。

ちなみに、緑帯においてセッション名の右側には、ヰンドウ名が表示されている。ヰンドウが複数あるならば、- でなく * 印がついているほうが現在表に出ているヰンドウである。一方ペイン名は緑帯に出ていないので、これを知るためには Ctrl-b q と打鍵すると、緑帯画面にペイン名が素敵な方法で一瞬だけ表示される。

ただし、クライアント名を知る必要はない場合が少なくない。たとえば、現在アクティブなペインから、tmux detach-client と打鍵するか、C-b d と打鍵すると、目の前にいるクライアントがデタッチされるからだ。こうしたことはクライアント名を知らなくてもできる。

クライアントのセッションへのアタッチとデタッチ

やっとこれで、tmux の著しい特徴を試してみる準備が整った。

デタッチ

tmux では「クライアントをセッションにアタッチする」「クライアントをセッションからデタッチする」という表現をする。国語的に考えてみると、この表現は、クライアントが存在しなくともセッションが存続しうることを示唆しているように読める。そして、それは正しい。

われわれの例でいうなら、サーバ・プロセスである tmux(5) 配下の bash プロセスたちは、クライアント・プロセスである tmux(4) や tmux(10) が存在しなくとも、生き存えうることは容易に予想できる。

さらに、これまでいいかげんな説明をしてきたから、ヰンドウやペインは tmux(4) や tmux(10) が管理しているような印象を与えたかもしれないが、それはそういう気分になるというだけの話であって、じつはそれらを表示するためのクライアントがなくても、ヰンドウやペインはサーバ側の tmux(5) によって管理され続けているのである。

ではさっそく、tmux detach-client -t pts/1 を打鍵してみる。緑帯画面その 1 が消滅する。プロセス・ツリーから pts/1 に接続されていた tmux(4) が消滅しているのがわかる。(ちなみに、detach-client を打つとき -t オプションでクライアントを明示しない場合、暗黙のうちに、いま自分が相手にしているクライアントがデタッチされる。ふつうは、これを利用することが多いだろう)

  systemd(1)-+-...---xterm(2)---bash(3)  (ここ消えた) 
     |       |
     |       +-...---xterm(8)---bash(9)---tmux(10)
     |
     +--- tmux(5)-+-bash(6)---vim(7)   ←(消えてない)
                  | 
                  +-bash(11)
		  |
		  +-bash(12)   ←(消えてない)
		  |
		  +-bash(13)

tmux(4) は消えてなくなったが、彼と仲良しだった bash(6) (やその配下の vim(7))、bash(12) は健在である。サーバ・クライアントの関係に注目してプロセスツリーを書き直すと、

              サーバ側     (ソケット通信)  クライアント側
    +------------------------------------------------------+
    |                                                      |
    +----> tmux(5)-+-bash(6)---vim(7)                      |  
                   +-bash(12)                              |  
		   |                                       |
                   +-bash(11)                tmux(10) <----+  緑帯画面2 ペイン1
                   +-bash(13)                                           ペイン2

というような具合になる。2 つ立ち上がっていたクライアントのうちの 1 つをセッションからデタッチした状態だ。

アタッチ

いまも、bash(6) と vim(7) の制御端末は pts/2 であり、bash(12) の制御端末は pts/6 であり続けているが、この pts/2 や pts/6 に私のキー入力を流してくれるクライアント tmux(4) はもはや存在しないのだ。したがって、通常のやり方では、われわれはこれらのプロセスとは二度と出会うことができない。しかし、tmux の新しいクライアント・プロセスを作成して、以前のように私のキー入力を pts/2 や pts/6 に伝えてもらうようにすることが可能である。より包括的・抽象的な言い方をするなら、セッション 0 に対して、新規 tmux クライアントをアタッチすることが可能となるのだ。

さっそく、tmux attach-session -t 0 と打鍵してみる。(これを打鍵するターミナルエミュレータは、tmux(10) が支配しているそれではないほうがよい。というのは、入れ子状態になるとやっかいだからだ。)。前と同じ 0 というセッション名で、前と同じように 2 つのヰンドウが戻ってきた! ヰンドウ 0 で動いていた vim も、健在だ。記念にプロセスツリーを見てみる。

  systemd(1)-+-...---xterm(2)---bash(3)---tmux(14)
     |       |
     |       +-...---xterm(8)---bash(9)---tmux(10)
     |
     +--- tmux(5)-+-bash(6)---vim(7)
                  | 
                  +-bash(11)
		  |
		  +-bash(12)
		  |
		  +-bash(13)

プロセス番号こそ違え(tmux(4) から tmux(14) になっている)、何もかも昔のままだ。

その他

なお、クライアントをセッションからデタッチするのではなく、セッションそのものを消滅させることもできる。「tmux kill-session -t セッション名(あるいはセッションID)」だ。-t 以下を省略すれば、現在自分が相手にしているセッションを消滅させる。そのセッションを担当していたクライアント・プロセスが消滅するだけでなく、サーバプロセス以下にぶら下がっている、そのセッションに関連したプロセスもいっせいに消滅する。

また tmux kill-window コマンドは、現在自分がいるヰンドウ(または -t オプションで指定されたヰンドウ)を消去し、それに対応したサーバ側のシェルのプロセス(およびその子孫プロセス)も消滅させる。同様に、tmux kill-pane とういコマンドがある。

ヰンドウだけ、ペインだけを「デタッチ」するというようなことはできない。デタッチという動詞の目的語は、常にクライアント・プロセスなのである。

すべてを消滅させるには、tmux kill-server を打鍵する。そうすれば、サーバ・プロセスもクライアント・プロセスも、すべて消えてなくなる。

tmux switch-client は、いずれかのセッションを(-t オプションで指定。デフォルトは目下接続しているセッション)に、すでに立ち上がっているいずれかのクライアント(-c オプションで指定。デフォルトでは目下使っているクライアント)を接続させる。「switch-session というコマンドがないなあ……」と思ったら、必要としているのはたぶんこのコマンド。

tmux をシェル・スクリプトから起動する

tmux start-server をすると、tmux サーバが立ち上がる。セッションは作成されない——というようなことが man tmux に書いてあるけれども、私のとこではこのコマンドを打っても何も起こらない。その代わり、セッションを作成すると自動的にサーバが立ち上がる。

tmux new-session は、セッションを作成する。-d オプションをつけない場合、クライアント・プロセスが作られ、セッションはこれにアタッチされる。-d オプションをつけたならば、クライアントは立ち上がらない。

シェル・スクリプト中で、tmux new-session は、-d オプションつきで書かれることが多い。というのは、もし -d オプションがなければ、この時点で tmux のクライアントが(スクリプトを実行しているシェルの子プロセスとして)フォアグラウンドで立ち上がり、シェルスクリプトの残り部分は、クライアント・プロセスが終了するまで実行されることがないからである。同様の理由から、tmux を起動するスクリプトにおいて、クライアントを立ち上げてセッションにアタッチするコマンドは、その最後にもっていかなくてはならない。

面白いのは -t オプションで、これにはターゲット・セッションを指定する。これを指定すると、立ち上がったセッションは指定されたセッションとグループ化され、さまざまなリソースを共有し、その結果、まるでセッションのハードリンクができたような状態になる。こうしてグループ化された 2 つのセッションのうち片方を tmux kill-session しても、もう片方は生き残る。

tmux new-session をするとき、セッション名は、-s で指定することができる。また、オプション -n でウィンドウ名を指定することができる。セッションを作成したら、必ずウィンドウが 1 つ作成されるので、そのウィンドウの名前を -n オプションによって決めてやるのである(それをしなければ、ウィンドウ名は 0 になる)。ペインは名前を持たないから、ペインに対してはそういう仕組は存在しない。

tmux split-window は、ウィンドウにペインを 1 つ追加する。このとき、-t オプションで指定するのは、ターゲットとなるペインである。指定されたペインの後ろ(デフォルトでは下に、-v オプションがあるなら右に)にもう新たなペインが追加されるのだ(-b オプションをつけると、「前に」追加される)。ウィンドウがあるならば、少なくとも 1 つのペインがその下にあることを考えれば、これが理解できる。tmux split-window の対象となるペインを持つセッションが、いずれかのクライアントにアタッチされている必要はないの。われわれが分割されたウィンドウにお目にかかれるのは、そのセッションがアタッチされた後である。

tmux send-keys は、-t オプションで指定したペインに対してキー入力があったように装う。

いま、tmux new-session -d -n test-session を行い、アタッチされていない test-session という名前のセッションが 1 つあるとする。このセッションを tmux attach-session -t test-session とすると、やっと、起動したターミナルに緑帯画面が現れる。

これらを使って、画面の上で tail -f test.txt を、画面の下で cat > test.txt を行うシェルスクリプトを書いてみるならば、

tmux start-server # 私の環境では、これは不要だ
tmux new-session -d -s "mysess" -n "mywin" # セッション作成時に暗黙に作られる
                                           # ウィンドウ名を mywin にする。
tmux split-window -t mysess:mywin.0 -l 3  # mysess セッション下の mywin ウィン
                                          # ドウ下のペイン 0 の下に 3 行からなる新しい
                                          # ペインを作成する。
tmux send-keys -t mysess:mywin.0 "tail -f test.txt" C-m
tmux send-keys -t mysess:mywin.1 "cat > test.txt" C-m
tmux attach-session -t mysess     # クライアントを立ち上げ mysess セッションに
                                  # アタッチする

という具合になる。(これは、下段で入力した文字を上段に追加していくだけの仕組みだ。)

GNU screen は tmux とどう違うのさ

screen と打鍵して、screen を起動する。tmux は画面に緑帯が現れたが、screen では画面はいつもと変わらないように見える。

pstree -p で確認すると、プロセス・ツリーは以下のごとし。赤字にしたところが、新たに発生したプロセスだ。

-xterm(29971)---bash(29973)---screen(30840)---screen(30841)---bash(30842)
        ?           pts/4       pts/4            ?             pts/6

ここで、screen -ls でセッションを確認すると、主要部分は以下のごとし。

30841.pts-4.my-desktop (タイムスタンプ) (Attached)

ここでいったん screen -d 30841 でデタッチをしてみる。プロセスツリーは

...-xterm(29971)---bash(29973)
        ?            pts/4         
-screen(30841)---bash(30842)
     ?             pts/6

のようになる。再び screen -r 30841 としてアタッチしてみると、プロセスツリーは次のごとし。

...-xterm(29971)---bash(29973)---screen(30890)
        ?            pts/4         pts/4
-screen(30841)---bash(30842)
        ?             pts/6

ここで xterm(29971) の画面から echo $$ をやってみると、30842 となっている。そして、tty を打ってみると、pts/6 である。

この状態は、プロセス・ツリーの面から見ると、tmux のそれとまったく同じである。

(ここで書く力尽きにけり)

おわり