web-dev-qa-db-ja.com

"LC_ALL = C"は何をしますか?

UnixライクなシステムでLC_ALLC値は何をしますか?

私はそれがすべての面で同じロケールを強制することを知っていますが、Cは何をしますか?

344
jcubic

これにより、アプリケーションは出力にデフォルトの言語を使用します。

$ LC_ALL=es_ES man
¿Qué página de manual desea?

$ LC_ALL=C man
What manual page do you want?

ソートを強制的にバイト単位にします。

$ LC_ALL=en_US sort <<< $'a\nb\nA\nB'
a
A
b
B

$ LC_ALL=C sort <<< $'a\nb\nA\nB'
A
B
a
b
228

_LC_ALL_は、他のすべてのローカリゼーション設定をオーバーライドする環境変数です( 状況によっては_$LANGUAGE_を除く )。

いくつかの環境変数を使用して、ローカリゼーションのさまざまな側面(1,000区切り記号または小数点文字、文字セット、並べ替え順序、月、曜日の名前、言語またはアプリケーションメッセージ(エラーメッセージ、通貨記号など))を設定できます。

通常、_$LANG_は、地域を識別する値(UTF-8を使用してフランス語圏のスイスにいる場合は_fr_CH.UTF-8_など)を使用して設定します。個々の_LC_xxx_変数は、特定の側面をオーバーライドします。 _LC_ALL_はそれらすべてをオーバーライドします。 localeコマンドを引数なしで呼び出すと、現在の設定の概要が表示されます。

たとえば、GNU=システムでは、次のようになります。

_$ locale
LANG=en_GB.UTF-8
LANGUAGE=
LC_CTYPE="en_GB.UTF-8"
LC_NUMERIC="en_GB.UTF-8"
LC_TIME="en_GB.UTF-8"
LC_COLLATE="en_GB.UTF-8"
LC_MONETARY="en_GB.UTF-8"
LC_MESSAGES="en_GB.UTF-8"
LC_PAPER="en_GB.UTF-8"
LC_NAME="en_GB.UTF-8"
LC_ADDRESS="en_GB.UTF-8"
LC_TELEPHONE="en_GB.UTF-8"
LC_MEASUREMENT="en_GB.UTF-8"
LC_IDENTIFICATION="en_GB.UTF-8"
LC_ALL=
_

たとえば、個々の設定を次のようにオーバーライドできます。

_$ LC_TIME=fr_FR.UTF-8 date
jeudi 22 août 2013, 10:41:30 (UTC+0100)
_

または:

_$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€
_

または、すべてをLC_ALLでオーバーライドします。

_$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory
_

スクリプトで、特定の設定を強制したい場合、ユーザーが強制した設定(おそらくLC_ALLも)がわからないため、LC_ALLを強制するのが最も安全で一般的な唯一のオプションです。

Cロケールは、最も単純なロケールであることを意図した特別なロケールです。他のロケールは人間用であり、Cロケールはコンピュータ用であるとも言えます。 Cロケールでは、文字は1バイトであり、文字セットはASCII(まあ、必須ではありませんが、実際にはほとんどの人が使用するシステムにあります)、ソート順はバイト値に基づいており、言語は通常米国英語です(ただし、アプリケーションメッセージの場合(月または日の名前やシステムライブラリによるメッセージなどではなく)、アプリケーション作成者の裁量による)および通貨などシンボルは定義されていません。

一部のシステムでは、たとえば非ASCII文字のソート順序が定義されていないPOSIXロケールとの違いがあります。

通常、LC_ALL = Cを指定してコマンドを実行し、ユーザーの設定がスクリプトに干渉しないようにします。たとえば、_[a-z]_をaからzまでの26個のASCII文字に一致させるには、_LC_ALL=C_を設定する必要があります。 。

GNUシステムでは、_LC_ALL=C_および_LC_ALL=POSIX_(または_LC_MESSAGES=C|POSIX_)は_$LANGUAGE_をオーバーライドしますが、_LC_ALL=anything-else_はオーバーライドしません。

通常_LC_ALL=C_を設定する必要があるいくつかのケース:

  • _sort -u_または_sort ... | uniq..._。 C以外の多くのロケールでは、一部のシステム(特にGNU ones))では、 一部の文字は同じ並べ替え順を持っています です。_sort -u_は一意を報告しません行ですが、並べ替え順序が等しい行の各グループの1つです。したがって、一意の行が必要な場合は、文字がバイトで、すべての文字が異なる並べ替え順序を持つロケールが必要です(Cロケールはこれを保証します)。 。
  • 同じことがPOSIX準拠の_=_演算子exprまたはPOSIX準拠の_==_演算子awks(mawkおよびgawkその点ではPOSIXではありません)。2つの文字列が同一であるかどうかはチェックされませんが、同じようにソートされるかどうかはチェックされません。
  • grepのような文字範囲。ユーザーの言語の文字と一致させる場合は、_grep '[[:alpha:]]'_を使用し、_LC_ALL_は変更しないでください。ただし、_a-zA-Z_ ASCII文字に一致させる場合は、_LC_ALL=C grep '[[:alpha:]]'_または_LC_ALL=C grep '[a-zA-Z]'_¹のいずれかが必要です。_[a-z]_は、並べ替え後の文字に一致しますa以前z(ただし、多くのAPIを使用すると、それよりも複雑になります)。他のロケールでは、通常、それらが何であるかがわかりません。たとえば、一部のロケールでは、並べ替えの大文字と小文字を区別しません_[a-z]_ bashパターンなどの一部のAPIでは、_[B-Z]_または_[A-Y]_を含めることができます。多くのUTF-8ロケール(ほとんどのシステムの_en_US.UTF-8_を含む)では、_[a-z]_には、発音区別符号付きのaからyまでのラテン文字が含まれますが、zの文字は含まれません(zはそれらの前にソートされるため)。想像してみてください(なぜ_é_ではなく_ź_を含めたいのですか?)。
  • _ksh93_の浮動小数点演算。 _ksh93_は、_decimal_point_の_LC_NUMERIC_設定を優先します。 a=$((1.2/7))を含むスクリプトを記述した場合、ロケールに小数点記号としてカンマが含まれているユーザーが実行すると、スクリプトが機能しなくなります。

    _$ ksh93 -c 'echo $((1.1/2))'
    0.55
    $ LANG=fr_FR.UTF-8  ksh93 -c 'echo $((1.1/2))'
    ksh93: 1.1/2: arithmetic syntax error
    _

    次に、次のようなものが必要です:

    _#! /bin/ksh93 -
    float input="$1" # get it as input from the user in his locale
    float output
    arith() { typeset LC_ALL=C; (($@)); }
    arith output=input/1.2 # use the dot here as it will be interpreted
                           # under LC_ALL=C
    echo "$output" # output in the user's locale
    _

    補足:_,_小数点記号は_,_算術演算子と競合し、さらに混乱を招く可能性があります。

  • 文字をバイトにする必要がある場合。現在、ほとんどのロケールはUTF-8ベースです。つまり、文字は1〜6バイトを取ることができます。バイトを目的とするデータを処理する場合、テキストユーティリティを使用する場合は、LC_ALL = Cを設定する必要があります。 UTF-8データの解析にはコストがかかるため、パフォーマンスも大幅に向上します。
  • 前のポイントの帰結:入力がどの文字セットで書かれているかわからないテキストを処理するとき、入力がASCIIと互換性があると想定できます(ほとんどすべての文字セットがそうであるように)。) _grep '<.*>'_、_<_のペアを含む行を検索するインスタンス_>_は、UTF-8ロケールで、入力がシングルバイトの8ビットでエンコードされている場合は機能しませんiso8859-15のような文字セットです。これは、_._が文字にのみ一致し、iso8859-15の非ASCII文字がUTF-8で有効な文字を形成しない可能性が高いためです。一方、_LC_ALL=C grep '<.*>'_はバイト値はCロケールで有効な文字を形成するため、機能します。
  • 人間を対象としたものではない入力データまたは出力データを処理するとき。ユーザーと話している場合は、ユーザーの慣習と言語を使用できますが、たとえば、英語スタイルの小数点または英語の月名を期待する他のアプリケーションにフィードするためにいくつかの数値を生成する場合は、 LC_ALL = Cを設定します。

    _$ printf '%g\n' 1e-2
    0,01
    $ LC_ALL=C printf '%g\n' 1e-2
    0.01
    $ date +%b
    août
    $ LC_ALL=C date +%b
    Aug
    _

    これは、大文字と小文字を区別しない比較(_grep -i_など)や大文字と小文字の変換(awk 's toupper()、_dd conv=ucase_...)などにも適用されます。例えば:

    _grep -i i
    _

    ユーザーのロケールのIでの一致は保証されていません。たとえば一部のトルコ語ロケールでは、大文字のiは_İ_(ドットに注意)であり、小文字のIは_ı_(ドットがないことに注意してください)。


theただし、テキストのエンコードによっては、必ずしも正しいこととは限りません。これは、UTF-8またはシングルバイト文字セット(iso-8859-1など)に有効ですが、UTF-8以外のマルチバイト文字セットである必要はありません。

たとえば、_zh_HK.big5hkscs_ロケール(香港、BIG5中国語文字エンコーディングの香港版を使用)で、その文字セットでエンコードされたファイルで英語の文字を検索するには、次のいずれかを実行します。 :

_LC_ALL=C grep '[[:alpha:]]'
_

または

_LC_ALL=C grep '[a-zA-Z]'
_

その文字セット(および他の多くの文字列ですが、UTF-8が登場して以来ほとんど使用されていません)では、対応する多くの文字containバイトが含まれるため、誤りですASCII A-Za-z文字のエンコーディング。たとえば、_A䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽_(およびその他多数)のすべてにAのエンコーディングが含まれています。__は0x96 0x41であり、AはASCIIのように0x41です。したがって、_LC_ALL=C grep '[a-zA-Z]'_は、これらの文字列を含む行で一致し、バイトシーケンスを誤って解釈します。

_LC_COLLATE=C grep '[A-Za-z]'
_

機能しますが、_LC_ALL_が他に設定されていない場合のみ(_LC_COLLATE_をオーバーライドします)。だからあなたはやらなければならないかもしれません:

_grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'
_

ロケールのエンコーディングでエンコードされたファイルで英語の文字を検索したい場合。

359

Cはデフォルトのロケールで、「POSIX」は「C」のエイリアスです。 "C"はANSI-Cに由来すると思います。たぶんANSI-Cは "POSIX"ロケールを定義しています。

8
Edward Shen

私の知る限り、OS XはUTF-8ロケールでコードポイントの照合順序を使用するため、StéphaneChazelasの回答で言及されているいくつかのポイントの例外です。

これにより、OS Xでは26、Ubuntuでは310が印刷されます。

export LC_ALL=en_US.UTF-8
printf %b $(printf '\\U%08x\\n' $(seq $((0x11)) $((0x10ffff))))|grep -a '[a-z]'|wc -l

以下のコードはOS Xでは何も出力せず、入力がソートされていることを示しています。削除された6つのサロゲート文字により、不正なバイトシーケンスエラーが発生します。

export LC_ALL=en_US.UTF-8
for ((i=1;i<=0x1fffff;i++));do
  x=$(printf %04x $i)
  [[ $x = @(000a|d800|db7f|db80|dbff|dc00|dfff) ]]&&continue
  printf %b \\U$x\\n
done|sort -c

以下のコードはOS Xでは何も出力せず、同じ照合順序を持つ2つの連続したコードポイント(少なくともU + 000BとU + D7FFの間)がないことを示しています。

export LC_ALL=en_US.UTF-8
for ((i=0xb;i<=0xd7fe;i++));do
  printf %b $(printf '\\U%08x\\n' $((i+1)) $i)|sort -c 2>/dev/null&&echo $i
done

(上記の例では%b理由はprintf \\U25はzshでエラーになります。)

GNUシステムでは照合順序が同じである一部の文字および文字シーケンスは、OS Xでは同じ照合順序ではありません。これにより、OS Xで最初に①が出力されます(OS XのsortまたはGNU sort)ですが、②Ubuntuで最初に:

export LC_ALL=en_US.UTF-8;printf %s\\n ② ①|sort

これはOS Xで3行(OS XのsortまたはGNU sortを使用)を出力しますが、Ubuntuでは1行を出力します。

export LC_ALL=en_US.UTF-8;printf %b\\n \\u0d4c \\u0d57 \\u0d46\\u0d57|sort -u
4
nisetama

LC_COLLATEは、lsによって使用される「アルファベット順」も制御します。 USロケールは次のようにソートされます。

a.C
aFilename.C
aFilename.H
a.H

基本的に期間を無視します。あなたが好むかもしれません:

a.C
a.H
aFilename.C
aFilename.H

私は確かにそうします。設定LC_COLLATE to Cはこれを実現します。また、すべての大文字の後に小文字で並べ替えます。

A.C
A.H
AFilename.C
a.C
a.H
4
SteveInCO