6. あなたのシステムですべきこと

繰り返すが、システムを直そうとする人々が混乱する主な原因は、 たいてい間違った箇所を直そうとしているからだ。正常に作動しているように 見える部分は偶然そう見えるだけなことも多いので、ある箇所が壊れていると 思って修理をすすめると、正しい設定を間違った設定に変更してしまう ことがよく起こりがちだ。

6.1. やらねばならないこと

6.1.1. 微妙にずれてるアレの検出

綺麗な解決法への最初のステップは、まずどの端末が異常で どれが正常かをはっきりと知ることだ。普通、端末は全てコンソールのように 振る舞うので、その場合は全体を正常にするための変更は最小で済む。 だがもしアレゲ端末 (例えばアレゲバージョンの gnome-terminal) を使っている場合は、 特殊な扱いが必要となる。

次の C の一行プログラム

void main(void) {int c; while(c = getchar()) printf("%d 0x%02X\n", c, c);}
が役に立つかもしれない。この 1 行を ascii.c という名のファイルに記録し、gcc ascii.c -o ascii でコンパイルした後、./ascii とタイプして実行し、 何かキーを押してから RETURN を押してみよ。 このプログラムは 10 進法と 16 進法で、発生した ASCII 文字列を表示する (stty erase ^- を最初に行っておけば、実際のコード全てが得られる)。これで Backspace が何をするか簡単に見られるようになった。もしそれが DEL (127) を出力するならそれは標準的な端末、 もし BS (8) ならばアレゲ端末、ということになる。

6.1.2. 各エミュレータの分別

アレゲ端末エミュレータを使っている場合は、それらを 標準的なものと区別せねばならない。理論上はこれは可能なはずだ。 なぜなら端末データベースには異なったシーケンスを持つ端末のためのエントリが 数種類あるからだ。

ここで我々が取るアプローチは、gnome エントリを すべてのアレゲ端末に、xterm エントリをすべての 標準端末に用いる、というものである。このやり方は大抵のディストリビューションで うまくいく (5.0 以前の Red Hat のような xterm エントリがアレゲな一部例外を除く)。

だが、gnome-terminal はデフォルトで xterm と同じエントリを使用する。 よってもし一方がアレゲで、もう一方がそうでない場合、 それらを分離するための方法を探す必要がある。理論的には gnome-terminaltermname オプションでユーザは TERM 変数をより相応しい名前に 変更することが可能なはずだが、現在 gnome-terminal 1.2.1 においてこのオプションは動作しない。

ここで一つよいアイデアを。gnome-terminalCOLORTERM 変数を gnome-terminal に設定することを利用するのだ。 だから、簡単なテストをシェルの設定ファイルに追加すれば、 TERM 変数を修正することが可能だ。

6.1.3. 端末データベースの修正

次の問題は端末データベースにアレゲ端末向けの gnome エントリが存在しない可能性があることだ (これは termcapterminfo のいくつものバージョンで起こりうる)。 最近の terminfo データベースには gnome エントリがあるはずだが、いずれにせよ gnome-terminal は基本的には xterm で、例のキー二つが違うだけだ。 だから、ちょっとした仕掛けで正しいエントリを新たに生成することは 可能なはずだ。

6.1.4. シェル動作の修正

bash など多くのプログラムで入力行を 読むのに使用されている readline ライブラリは、 指定したシーケンスを認識するようにカスタマイズすることが可能だ。 この変更は TERM 変数によって制御することも可能なので、 一度端末の分別が済めば、より細かいチューニングをキーボードに 施すことができる。

さらに、もし less などの raw 行入力を 行うアプリケーションを正常に動作させたければ、 アレゲ端末エミュレータでは削除文字は BS であり、 DELではないのだとシェルに理解させなければならない (標準端末なら Backspace キーは既に DEL を発信しているから、何もする必要はない)。 これは stty コマンドを用いることで実現可能だ。

6.2. 実践方法

注意

これらの修正方法には幾つか欠点がある。まず、これらは特定の 端末でしか機能しない。また、理論上 (実際に起こることは稀なのだが) これらは他の端末の readline ライブラリを 混乱させる可能性がある。 もっとも、これらの制限はほとんどの場合は問題にならない。

まず infocmp gnome として、既に gnome エントリが terminfo データベースに 存在しているかどうかを確認する (termcap は後で修正する)。エントリが存在しなければ、以下のコマンド

bash$ tic <(infocmp xterm |\
        sed 's/xterm|/gnome|/' |\
        sed 's/kbs=\\177,/kbs=^H,/' |\
        sed 's/kdch1=\\E\[3~,/kdch1=\\177,/')
を用いれば ~/.terminfo に正しいエントリが作成される。 もし同じコマンドが root により実行されると、グローバルデータベースに エントリが作成される (この動作は TERMINFO~/.terminfo に設定すれば変更できる)。 もし xterm エントリが既にアレゲである場合は (例えば 5.0 以前の Red Hat の場合)、このスクリプトはそのエントリを変更せずに そのままコピーしてくれる。これは望みどおりの動作だろう。

次に以下の一行を ~/.inputrc [1] に追加する。

"\e[3~": delete-char
この一行は readline ライブラリに、標準 Delete キーを標準的なエミュレータでどのように扱うかを指示する。 運がよければ他の端末とは干渉しないだろう。だが、次にライブラリに対し DEL 文字がアレゲ端末上で何を意味するか説明せねばならない。 例えば以下の 3 行を ~/.inputrc に追加する。

$if term=gnome
DEL: delete-char
$endif
もし xterm がアレゲである場合も、 それに対応する 3 行を追加せねばならない。一方もしアレゲな 端末エミュレータがなければ、この作業は必要ない。 これらの変更は /etc/inputrc ファイルを変更すれば グローバルに有効になる。

TERM 変数が正しく設定されていれば、 条件付き割り当てを使うことでアレゲ端末を正しく動作させることは可能だ。 これを確かめるにはいくつもの方法がある。まず gnome-terminal での TERM 変数の デフォルト値は xterm だから、もしアレゲ端末が 存在しないければ、我々は何もしないでよい。だが、もし xterm をデフォルトにしているアレゲ端末が存在する場合、TERM 変数を 正しく設定する方法を見つけなければならない - gnome-terminal がこれに当てはまるとしよう。

もっとも簡単に TERM 変数の設定を行うには、 gnome-terminal--termname=gnome 引数付きで起動すればよい。これは GNOME パネル上のラウンチャーに正しいコマンドラインを 設定することなどで可能だ。もし古いバージョンを使っている場合、 この方法は動作しないかもしれない。その場合以下の数行を

if [ "$COLORTERM" = "gnome-terminal" ]
then
    export TERM=gnome
fi
~/.bashrc 設定ファイル [2] に追加すればよい。 この割り当ては gnome-terminal 上でのみ実行され、 TERM 変数を正しく設定する。

注意: 端末を gnome に設定すると、 ls は色表示を行わなくなる。 多くのバージョンの lsgnome-terminal の色特性を知らないためだ。 これを避けるには、 ~/.dircolors 設定ファイルを dircolors --print-database >~/.dircolors として作成し、 設定ファイルに TERM=gnome という一行を追加すればよい。

アレゲな端末エミュレータ向けの termcap エントリを動的に作成させることもできる。以下に手順を説明する。 いつものように、 ~/.bashrc に追加する:

if [ "$TERM" = "gnome" ]
then
    export TERMCAP=$(infocmp -C gnome | grep -v '^#' | \
                    tr '\n\t' '  ' | sed 's/\\  //g' | sed s/::/:/g)
fi

最後に、削除キーにより生成される文字を端末デバイスに 教えてやらねばならない。削除キーは通常バックスペースであると期待されているために、 標準的な端末エミュレータではこれは DEL 文字になる。 だからまずそのようにセットしてから、各アレゲ端末用の条件文を追加していく。 いつも通り ~/.bashrc に追加する:

stty erase ^?

if [ "$TERM" = "gnome" ]
then
    stty erase ^H
fi
もし全ての端末エミュレータがアレゲならば、 削除文字を条件なしで設定してももちろん構わない。

注意: 一部のディストリビューションは、既にこの修正をシステムワイドな /etc/inputrc 設定ファイルなどに施していることがある。 この場合 ~/.inputrc から不要になった行を 削除することもできる。

6.3. tcsh向けの修正

tcsh の場合、修正は全部 ~/.tcshrc に施す必要がある。 以下のように bash の場合と似ている -

bindkey "^[[3~" delete-char

if ($?COLORTERM) then
   if ($COLORTERM == "gnome-terminal") then
      setenv TERM gnome
   endif
endif

stty erase ^?

if ($?TERM) then
   if ($TERM == "gnome") then
      setenv TERMCAP \
       "`infocmp -C gnome | grep -v '^#' | tr '\n\t' '  ' | sed 's/\\  //g' | sed s/::/:/g`"
      bindkey "\177" delete-char
      stty erase ^H
   endif
endif
二つ目の部分は全てのアレゲ端末用に複製せねばならない。 当然、termcap が既に存在するなら作成する 必要はない。

注意

[1]

古いバージョンの bash では、 INPUTRC を正しく設定する必要があることを覚えておこう。 例えば

export INPUTRC=~/.inputrc
という行を ~/.profile (またはそれ以外のログインシェルのみが 読み込むファイル) に追加する。

[2]

より正確には、ログインシェルだけでなく全てのシェルに読み込まれる シェル設定ファイルに、だ。どれが正しいファイルかは、 bash のスタートアップシーケンスに依存する。