2015年1月13日火曜日

Macでロケール環境変数を設定しようとした話

せっかくUbuntuサーバに日本語パッケージを入れたんだから、Ubuntu本体のシェルでは日本語入力できなくても、Macからsshで繋いで使えればいいだろうと思っていた。
Apple Terminalではクライアント側にシェルがあるので、Macの日本語入力メソッドがそのまま使える。
ちなみに、X11環境もあるのでxtermなどでも日本語を入力したかったのだが、サーバ側に日本語入力メソッドを導入しようと数日のあいだ奮闘して、挫折した。
とりあえずTerminalだけで我慢することにしたが、入力とは別に、一つ気になる点があった。
それはログイン時の言語設定だ。

Ubuntuでは、LANG=ja_JP.UTF-8とすると、dateコマンドやvimなど各ソフトウェアの表示が日本語になる、ことがある。
サーバ本体では日本語が文字化けしてしまうので、.bashrcにもLANG環境変数を特に設定せず、クライアント側で調整することにした。
(実は、シェル情報で条件分岐することにより、別のマシンだけ日本語にすることができるのだが、クライアントの言語環境を無視するのが気に食わず、グローバル化にこだわっている。)



しかし、sshでMacからUbuntuにログインすると、Macで日本語だったものが、英語環境に切り替わってしまう。
printenv LANGを実行すると、en_US.UTF-8と出る。
サーバのsshd_configには
AcceptEnv LANG LC_*
があるし、Macのssh_configには
SendEnv LANG LC_*
があるので、LANGが切り替わるのは単純に考えるとおかしい。
Macがローカルなときにprintenvを実行すると、ちゃんとLANG=ja_JP.UTF-8になっている。

よく見ると、ここでLC_のつく環境変数が一つも存在しないことに気がついた。
Terminalの設定で、「起動時にロケール環境変数を設定」としているのに設定されていないのは不思議だ。
少し古い情報では、そのチェックを外したりつけ直したりするという改善法が書いてあったが、そうしても特に変化が見られない。
さらに調べていたら、このような記述が見つかった。
「言語とテキスト」設定では、各ロケールカテゴリに相当する値を、個別に設定可能ですが、それらの設定値が、対応するロケール系環境変数 (LC_* や LANGUAGE) に反映されることはありません。(システムワイドなロケール設定 ~ Mac OS X (その1) - 彷徨えるフジワラ
ロケール環境変数といったらLC_*のことじゃないのだろうか。

このページからヒントを得て、export LC_ALL=ja_JP.UTF-8を実行してからログインすると、望み通りLANGが転送された。
どうやらlocaleの部分に原因があるらしい。
一体どこで記述されているのかまだ見つけられていないが、ログイン時に、サーバのデフォルトのロケール LC_ALL=en_US.UTF-8 が適用されてLANGが上書きされているようだ。

せっかく転送したLANGがすぐ上書きされるのはどうも悔しい。
なんとかLC_*もMac側で登録したい。
その値も固定するのではなく、システム設定に従うようにして。
とりあえずlocaleを実行してみると、結果は
LANG="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_CTYPE="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_ALL="ja_JP.UTF-8"
形として代入式になっているので、これを使おうと考えた。

試しに、
locale > a.tmp; while read line; do export $line; done < a.tmp
で、1行ずつ頭にexportをつけて設定してから、ログインしてみた。
しかしうまくいかず、LANGがまたリセットされた。
ログインした状態でlocaleを実行すると、
LC_COLLATE=\"ja_JP.UTF-8\"
などとなっていて、not foundエラーが出た。

そこで"を取り除くことにした。ついでにファイルを媒介しない方法にしようとした。
locale|while read line; do export `echo $line|sed -e "s/\"//g"`; done
でも今度はローカルでもLC_*が設定されない。
exportを'echo A'に変えると、localeから"を取り除いて行頭にAをつけた結果がしっかり出力されるので、exportは実行されているだろう。

パイプを使っていたのを、ファイル媒介に戻してみた。
locale > lcenv.tmp; while 〜〜 done < lcenv.tmp
なんと今度はうまくいった。
やってることは変わらないと思うのだが、どうしてだろう。
詳しい人にコメント求む。
これをローカルの.bashrcに追加しておくといいと思う。

どう考えてもこれだけやるのに時間をかけすぎた。
今日はもう眠いのでここまで。

(追記 13日10:49)
.bash_profileに以下の行を追加して、今のところ問題なく動作している。
lcenv(){
        tmpfile=`mktemp /tmp/lcenv.XXXXXX` || echo "failed to mktemp"
        locale > $tmpfile
        while read line
        do
                export `echo $line|sed -e "s/\"//g"`
        done < $tmpfile
        rm $tmpfile
}
lcenv || echo "failed in lcenv."

0 件のコメント:

コメントを投稿