2011/12/22

GNU Screenで端末文字コードを素早く切り替える

本記事は ターミナルマルチプレクサ Advent Calendar 2011 : ATND の22日目です。21日目は X環境のクリップボードやOS Xのペーストボードとtmuxのバッファを連携する方法 - それ、Gentooだとどうなる? でした。ターミナルマルチプレクサでクリップボードとの連携ができると作業効率がまた一段と加速しますよね。今回は開発版からすこし離れて、GNU Screen でのエンコーディングについて書いてみようと思います。

ウィンドウごとにエンコーディングを変更する

昨今の PC-UNIX 系のシステムであれば OS の LANG 環境変数の値は ja_JP.UTF8 が多いと思いますが、私の周りでは ja_JP.ujis なところも結構あります。アプリケーションのコードやミドルウェアの設定ファイル、データベースのキャラクタセットなども OS のそれとは揃っていないこともあると思います。

多言語をサポートしているページャやエディタ、データベースクライアントを使用していればとくに気にすることはないかもしれませんが、一時的にそこからエンコーディングが異なるファイルやデータを表示したいときに端末エミュレータの設定で文字コードを変更したりすることはありませんか?ないですか。そうですか。

私の場合、例えば OS は UTF8 だけどもデータベースのキャラクタセットが SJIS であるためログファイル等も SJIS で、それらを tail で監視したいときがあります。iconv や nkf を通せば良いのですが、パイプでつなぐと出力がバッファリングされるのでアレっ?と思うときがあります。そのような時は表示用として一時的に端末エミュレータの設定で文字コードを変換して表示するようにしていたこともあります。

同じことは GNU Screen でも可能で、ウィンドウごとにエンコーディングを設定できます。screen(1) には次のようにあります。

encoding enc [enc]

Tell  screen how to interpret the input/output. The first argument sets the encoding of the current window. Each window can emulate a different encoding. The optional second parameter overwrites the encoding of the connected terminal. It should never be needed as screen uses the locale setting to detect the encoding.  There is also a way to select a terminal encoding depending on the terminal type by  using  the "KJ" termcap entry.

Supported encodings are eucJP, SJIS, eucKR, eucCN, Big5, GBK, KOI8-R, CP1251, UTF-8, ISO8859-2, ISO8859-3, ISO8859-4, ISO8859-5, ISO8859-6, ISO8859-7, ISO8859-8, ISO8859-9, ISO8859-10, ISO8859-15, jis.

See also "defencoding", which changes the default setting of a new window.
とくに指定しない場合は screen を起動したときのロケールに基づいて設定されますので、UTF-8 な環境で起動した場合は encoding も UTF-8 になります。第二引数は設定したことが無いのでよく分かりませんが、文字コードにかなり詳しい以下のページによると、screen に接続している端末側の文字コードを変更できるようです。私にはイマイチ使いどころが分かりませんが、少なくとも通常の入出力を行うだけであれば第一引数を設定するだけで事足ります。

(追記) encoding の利用ケースとして、Cygwin で tree コマンドを表示するときに一時的に sjis に変更しているという情報がありました。一般的な cp932 とは異なる Cygwin 上で Windows 外部コマンドの出力を確認したいときなどは典型的なケースですね。まあ Cygwin 上で Screen を使うのは少数かも知れませんが、なるほど〜と思いました。

素早くエンコーディングを切り替える

とはいえ、エンコーディングを切り替えたい度に encoding eucjp などと打つのは苦痛です。当然何らかのキーにマッピングして使う事になりますので、参考までに私の設定を紹介したいと思います。(これが言いたかった!)

# to switch window encoding, and set the relevant environment variables.(for b-shell)
bind ^E eval 'command -c sencoding' 'echo "switch window encoding to: [u]tf8 [e]ucjp [s]jis / with env [U]tf8 [E]ucjp [S]jis"'
bind -c sencoding ^U eval 'encoding utf8'  'info'
bind -c sencoding u  eval 'encoding utf8'  'info'
bind -c sencoding ^E eval 'encoding eucjp' 'info'
bind -c sencoding e  eval 'encoding eucjp' 'info'
bind -c sencoding ^S eval 'encoding sjis'  'info'
bind -c sencoding s  eval 'encoding sjis'  'info'
bind -c sencoding U  eval 'encoding utf8'  '!!!echo "LANG=ja_JP.UTF-8; export LANG"' 'info'
bind -c sencoding E  eval 'encoding eucjp' '!!!echo "LANG=ja_JP.eucJP; export LANG"' 'info'
bind -c sencoding S  eval 'encoding sjis'  '!!!echo "LANG=ja_JP.sjis; export LANG"'  'info'
例によって多段キーバインドです。Ctrl-A Ctrl-E でエンコーディング設定モード(仮称)に移行して、(自分がよく使う)変更したいエンコーディングの頭文字でそのエンコーディングに変更し、最後に info でウィンドウ情報を表示して変更されたエンコーディングを確認できるようにしています。また頭文字を大文字で入力した場合はウィンドウのエンコーディング変換とともに、シェルの LANG 環境変数も変更するようにしています。(単に echo している文字がウィンドウに入力されるだけですので、シェルが入力待機状態でないと悲しい思いをします)

なお、私は Oracle Database を扱う環境での作業が多いので !!!echo のところは次のようにしています。このへんはシェルの話なので何とでも書けますね。

'!!!echo "LANG=ja_JP.UTF-8; export LANG; test -z \"\$NLS_LANG\" || { NLS_LANG=Japanese_Japan.AL32UTF8; export NLS_LANG; }"' 'info'
'!!!echo "LANG=ja_JP.eucJP; export LANG; test -z \"\$NLS_LANG\" || { NLS_LANG=Japanese_Japan.JA16EUC; export NLS_LANG; }"'  'info'
'!!!echo "LANG=ja_JP.sjis; export LANG; test -z \"\$NLS_LANG\" || { NLS_LANG=Japanese_Japan.JA16SJIS; export NLS_LANG; }"'  'info'

ちなみにここで設定している !!! は省略した exec の第一引数で、3文字で表すファイルディスクリプタ(順に標準入力、標準出力、標準エラー出力)の全てにおいて !(そのウィンドウで実行中のプロセス=大抵はシェルとか ssh コマンド)を指定しています。そして第二引数以降のコマンドをそのファイルディスクリプタに接続するという設定です。コピペして使っていたので詳細は理解できていません。screen(1) よりも詳しい情報を知りたい方は、以下ページに postscript ドキュメントの図解ありで詳しく載っています。

おわりに

さまざまエンコーディング環境においても、慌てず、騒がず GNU Screen でスマートに切り替えて作業が出来るよというお話でした。何かひとつでも端末作業における参考になることがあれば幸いです。

0 件のコメント:

コメントを投稿