彷徨えるフジワラ

年がら年中さまよってます

端末の文字コード

OpenSolaris デスクトップでは、ターミナルソフトとして gnome-terminal を使うのだけれど、どういうわけか gnome-terminal が対応している文字コードは基本 UTF-8 一択。標準テキストエディタの gedit は相当数の文字コードに対応しているのに…。

仕事/環境の都合上、EUC 作業環境に接続する必要があるため、この状況はなんとかしないとまずいことに。

ターミナルソフトを丸々入れ替えるのも有りって言えば有りなんだけど、「仲介しつつコード変換」的なアプローチの方が良さそう。しかし、cocot (Solaris 環境には非対応)とか luit (xterm に統合?)とかがそれっぽいけど、なかなか「コレ!」というのが無い。

暫く彷徨っていると、setterm なる Solaris コマンドが文字コード変換をやってくれるらしい、という話が聞こえて来た。
早速 setterm コマンドを実行してみようとしたら、そもそもコマンドがインストールされていない。"pkg search setterm" で調べてみると:

  • SUNWlang-common-extra
  • SUNWlang-ja-extra

あたりが必要らしい。

"pkg contents" で同梱ファイルを見たら、ロケール系ファイルもこれらのパッケージに含まれているみたい。ひょっとして、これらをインストールすれば gnome-terminal でも他の文字コードに対応するのかな?

お!「端末」→「文字コードの設定」で選択出来る!じゃ、後はこれを永続化して…………、どうやって?うわー、これ、.Xresources とか書かなきゃ駄目なの?面倒臭い…………。

気を取り直して setterm で進める方針で。まずは setterm を実行してみよう。

setterm: can't open config file "/usr/share/lib/setterm/C/conf.file"

????良くわからん。っつーか、setterm はマニュアルが一切無いのね。

あーだこーだ試行錯誤した末にやっとわかった。

例えば EUC 環境メインのリモートホストUTF-8 しか扱えない gnome-terminal で接続する場合、gnome-terminal 上のローカルシェルで:

  1. LC_CTYPE 環境変数を ja_JP.eucJP に設定
  2. "setterm -x UTF-8" を実行
  3. リモートホストSSH 等で接続

という手順を踏むと、ローカルシェルの tty レベルで EUCUTF-8 変換が実施される、という具合。

setterm コマンドで指定可能な変換先文字コードの一覧は、"setterm -v" で出力可能。それでもって先述したエラーは、LANG 設定を C ロケールで無効化していたことで:

変換可能な文字コード指定が無いよ?(意訳)

ということだったらしい。納得。

逆に、UTF-8 が使えないターミナルソフト(例: EUC なら取り扱い可能)で、UTF-8 メインの Solaris 環境に接続する場合も:

  1. Solaris 側で LC_CTYPE が ja_JP.UTF-8 であることを確認
  2. Solaris 側で "setterm -x EUC" を実行

という感じ。

個人的にはメッセージが日本語化されるのは好きじゃないので、ピンポイントで LC_CTYPE 環境変数を設定する方が好みだけど、ロケール設定の常として LANG や LC_ALL 等の一括指定も有効。

複数経路から接続する可能性のある Solaris サーバがあって:

  • UTF-8gnome-terminal 上の shell 環境からの ssh
  • UTF-8 未対応なターミナルソフトからの接続
  • screen コマンドで生成される新規シェル(TERM が screen)
  • 非対話的な ssh 実行(tty 不在)

とかの切り分けを Solaris サーバ側(setterm 可)で行いたい=接続元でゴチャゴチャやりたくない場合は:

if test x"${LC_MESSAGES}" != x && tty -s && test x"${TERM}" != x"screen"; then
    export LC_CTYPE=ja_JP.eucJP
    setterm -x UTF-8
fi

unset LC_MESSAGES
unset LC_CTYPE

みたいな感じの記述をリモート側の ~/.bashrc でしておけば大丈夫そう。但し上記のスクリプトは、接続元の UTF-8 性を、LC_MESSAGES 値有無で判定しているから、状況によってはこれを修正する必要がある。

最後に LC_CTYPE を unset してあるのは、ログイン後の screen コマンド実施の際に、新規生成される接続の文字コードが影響を受けるのを防ぐため。これをやらないと、ターミナルの文字コードをスルーさせるために、いちいち encoding 指定(引数2つ指定)をする必要がある。

表示だけなら気にしなくても大丈夫っぽいけど、マルチバイト文字の入力も行うなら、unset しておいた方が無難。っつーか、トラブル対処の簡便性からも、間に入るプログラムには極力文字コードスルーで処理して欲しいなぁ。

エンドポイント同士で符号化方式の合意が取れていれば、間はバイト列転送で済ませて欲しいんだけど、端末制御とかが絡んでくると、そうも言っていられないってことか?

ちなみに、ローカルホスト上で UTF-8gnome-terminal 越しに screen を使う場合の最短解は、-U 付き(UTF-8 モード稼動)での screen 起動、というのが悪戦苦闘の結論。

そういえば、less コマンドも文字コード判別に首を突っ込んで来る場合があるので、個人的には -r(ないし --raw-control-chars) オプション付きで alias をしておきたい感じ。