同じファイルを sort したのに、手元のマシンとサーバーで並び順が違った
中身は A、B、a、b、_c の5行
【疑問】sort の順番がマシンによって違う。LANG・LC_*・LC_ALL の優先順位と locale、文字コードと iconv【LPICレベル1】
前提のおさらい。環境変数はシェルから起動したコマンドに引き継がれて、ログインしたときに ~/.profile などの設定ファイルで決まる
>>1
ロケール(言語と地域の設定)の違い。並び順は LC_COLLATE で決まる。試した結果
LANG=C:A B _c a b(バイトの値の順)
LANG=en_US.UTF-8:a A b B _c(辞書の順。大文字小文字を並べて、記号は後回し)
>>3
ロケールって何を決めてるん
>>4
カテゴリごとに分かれてる
LC_CTYPE 文字の種類と文字コード、LC_COLLATE 並び順、LC_MESSAGES メッセージの言語、LC_NUMERIC 数の書き方、LC_TIME 日付と時刻の書き方、LC_MONETARY 通貨
今の設定は locale で全部表示される
>>5
数の書き方の違いも試した。printf "%'d\n" 1234567 が en_US.UTF-8 では 1,234,567、C では 1234567
>>5
LANG と LC_ALL とか LC_COLLATE とか、全部設定されてたらどれが効くん
>>7
LC_ALL がいちばん強くて、全部のカテゴリを上書きする。次が LC_COLLATE などの個別のもの、最後が LANG(ほかで決まってないカテゴリの既定値)
LC_ALL > LC_* > LANG
>>8
試したら、LC_ALL=C と LC_COLLATE=en_US.UTF-8 を両方付けて sort すると C の順(A B _c a b)になった。LC_ALL が勝つ
>>8
LC_ALL は普段の設定に使うもんやなくて、一時的に全部そろえたいときに使う
スクリプトの先頭で LANG=C とか LC_ALL=C とか書いてあるのを見るけど、なんで?
>>11
どのマシンで動かしても同じ結果にするため。sort の順番、grep の [a-z] の範囲、エラーメッセージの言語、小数点の記号などがロケールで変わる
エラーメッセージを grep で拾うスクリプトなんかは、メッセージが日本語になると動かなくなる
>>12
コマンド1つだけなら LC_ALL=C sort file みたいに前に付ければ、そのコマンドにだけ効く
>>4
ロケールの名前の ja_JP.UTF-8 ってどう読むん
>>14
言語_地域.文字コード。ja は日本語、JP は日本、UTF-8 が文字コード。C(POSIX と同じ)は最小限の英語のロケール
使えるロケールは locale -a。試したマシンは C、C.utf8、POSIX の3つだけやった。Debian は /etc/locale.gen を編集して locale-gen(か dpkg-reconfigure locales)で作る
>>15
システム全体の既定は Debian なら /etc/default/locale、Red Hat 系や systemd では /etc/locale.conf。localectl set-locale LANG=ja_JP.UTF-8 で変えられる(systemd が動いてないと使えない)
>>15
文字コードの UTF-8、ISO-8859、ASCII の違いは?
>>17
ASCII は7ビットで
文字。英数字と記号だけ
ISO-8859 は1文字1バイト(256通り)で、-1 が西ヨーロッパ、-5 がキリル文字のように地域ごとに分かれてる
UTF-8 は1文字1〜4バイトで、世界中の文字を扱える。ASCII の範囲はそのまま1バイト
>>18
od で見たら、é は UTF-8 で c3 a9 の2バイト、ISO-8859-1 で e9 の1バイト。あ は UTF-8 で e3 81 82 の3バイト
>>18
文字コードの変換は?
>>20iconv -f 元の文字コード -t 変換先の文字コード ファイルiconv -f UTF-8 -t ISO-8859-1 a.txt > b.txt
変換先にない文字があると止まる。あ を ISO-8859-1 にしたら illegal input sequence at position 0。-t ASCII//TRANSLIT にすると é は e、あ は ? に置き換わった
使える文字コードの一覧は iconv -l
>>21
Shift_JIS の古いファイルなら iconv -f SHIFT_JIS -t UTF-8。あ は Shift_JIS で 82 a0 やった
>>15
試したマシンには en_US と ja_JP のロケールがなかったから、/workspace の下の作業用ディレクトリに localedef で作って、LOCPATH でそこを指して試した。システムのロケールは変えてない
>>8
並び順は LC_COLLATE、強さは LC_ALL > LC_* > LANG、スクリプトは LC_ALL=C で固定、変換は iconv。サーバーとの違いはロケールやったわ
管理人のひとこと
- ロケールのカテゴリ:LC_CTYPE(文字の種類・文字コード)、LC_COLLATE(並び順)、LC_MESSAGES(メッセージ)、LC_NUMERIC、LC_TIME、LC_MONETARY など。確認は
locale、使えるものはlocale -a。 - 優先順位は LC_ALL > LC_* > LANG。LC_ALL は一時的に全部そろえるときに使う。名前は 言語_地域.文字コード(ja_JP.UTF-8)。C(POSIX)は最小限のロケール。
- スクリプトで LANG=C・LC_ALL=C を使うのは、sort の順・[a-z] の範囲・メッセージなどを環境によらず同じにするため(C では A B _c a b、en_US.UTF-8 では a A b B _c)。
- システム全体の設定は Debian が /etc/default/locale、Red Hat 系・systemd は /etc/locale.conf(localectl)。
- ASCII は7ビット(128文字)、ISO-8859-x は1バイトで地域ごと、UTF-8 は1〜4バイト。変換は
iconv -f 元 -t 先、一覧はiconv -l、//TRANSLIT で近い文字に置き換える。