LoginSignup
18
13

More than 5 years have passed since last update.

sortの挙動がロケールによって変わってハマる

Last updated at Posted at 2015-03-05

あらまし

お仕事の成果物チェックを find . -type f | sortdiff -qで比較して足りないファイルがないかチェックするようにした。

find . -type f | sort > files.txt
diff -q files-expected.txt files.txt

手元の環境で問題がなかったのでいざJenkinsで動かしたところ、
奇妙なことにまったく同じディストリビューション、コマンド、ファイルを入力に使ったにも関わらずエラーとなった。

調査

問題を最小化してみた。

手元
$ find . -type f | sort
A.txt
B.txt
a.txt
b.txt
Jenkins
$ find . -type f | sort
a.txt
A.txt
b.txt
B.txt

大文字と小文字の扱いが変わっているようだ。

原因

手元とJenkins環境を徹底的に調べたところ、LANGの値が異なった。

手元
$ echo $LANG
ja_JP.UTF-8
Jenkins
$ echo $LANG
en_US.UTF-8

検証

LANG=C
$ echo -e "a\nb\nA\nB"| LANG=C sort
A
B
a
b
LANG=ja_JP.UTF-8
$ echo -e "a\nb\nA\nB"| LANG=ja_JP.UTF-8 sort
A
B
a
b
LANG=en_US.UTF-8
$ echo -e "a\nb\nA\nB"| LANG=en_US.UTF-8 sort
a
A
b
B

やはりLANGが影響している。

sortLANGを見ているのか

sortのman pageにはLANGを見るとは一言も書いていない。

ではどこから差が来るのか

http://linux.die.net/man/3/strcoll
http://linux.die.net/man/3/setlocale

とてもわかりにくいが、整理すると以下のようになる。

  • strcoll()という文字比較関数が標準Cライブラリにある
  • この関数は、LC_COLLATEというロケールカテゴリによって挙動が変わる
  • ロケールを参照する場合、LC_COLLATEのカテゴリなら、LC_ALL, LC_COLLATE, LANGの順に値を見ていく

どうやらロケールの値は環境変数で変えられるようで、
今回はLANGの値が異なったことが原因で挙動が違ったようだ。

ロケールの値はlocaleで参照できる(コメント欄参照 THX @magicant

最後に

メジャーなコマンドラインツールが異なる挙動を示したらとりあえずlocaleを。

18
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
13