“LC_ALL = C”는 무엇을합니까?


324

유닉스 계열 시스템 의 C가치는 무엇입니까 LC_ALL?

나는 그것이 모든 측면에서 동일한 로케일을 강요한다는 것을 알고 있지만 무엇을 C합니까?


xclockwarning ( Missing charsets in String to FontSet conversion) 으로 문제를 해결 LC_ALL=C.UTF-8하려면 키릴 문제를 피하기 위해 사용 하는 것이 좋습니다 . 이 환경 변수를 설정하려면 ~/.bashrc파일 끝에 다음 줄을 추가해야 합니다. –export LC_ALL=C.UTF-8
fedotsoldier

@fedotsoldier 당신은 아마 질문을하고 스스로 대답을해야합니다. 나는 그것이 질문과 관련이 있다고 생각하지 않습니다. 그것은 당신이 겪고있는 다른 문제에 대한 대답입니다.
jcubic

네, 맞습니다.
fedotsoldier

답변:


209

응용 프로그램이 기본 언어를 사용하여 출력하도록합니다.

$ 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

20
좋은 예를 들어 +1이지만 Stephane의 답변에있는 중요한 정보가 부족합니다.
Olivier Dulac

4
기본 언어 는 무엇을 의미 합니까?
Stéphane Chazelas

2
예, 저자는 주석에 말하는 것을하지 않는 것을 포함하여 그가 좋아하는 모든 것을 할 수 있음을 이해합니다. 문제입니다. LC_ALL = C (LC_COLLATE)의 정렬 순서가 의미가있는 유일한 언어 인 LC_ALL = C (LC_TIME)에는 영어 월 및 일 이름이있는 언어 인 LC_ALL = C에서 문자 세트로 올바르게 표현할 수있는 유일한 언어는 미국 영어입니다. LC_ALL = C가 LC_ALL = en LANGUAGE = en과 다른 언어로 메시지를 반환 한 앱은 본 적이 없습니다. 그렇지 않은 경우 프로그램에 대한 버그를 신고 할 자격이 있습니까? (영어로 번역되지 않은 앱에 대해서는 언급하지 않음).
Stéphane Chazelas

2
문제는 "미국 영어는 LC_ALL = C의 문자셋으로 올바르게 표현할 수있는 유일한 언어"입니다. 좁은 문자를 사용할 때 C / C ++ 프로그램에서만 일반적으로 적용되지만 ASCII에서도 문자와 기호 만 사용하는 여러 언어가 있기 때문에 예외가 있습니다. 기본 언어가 영어가 아닌 경우 버그를보고하면 크게 눈에 띄게됩니다.
Ignacio Vazquez-Abrams

3
영어 (LANG = en_US.utf8의 의미)에서 메시지는 문자열 인용에“”와 같은 유니 코드 문자를 사용할 수 있으며 사용해야합니다. LANG = C에서 ASCII 따옴표 만 사용합니다 (큰 따옴표, 역 따옴표 및 아포스트로피).
Ángel

332

LC_ALL환경 변수는 다른 모든 현지화 설정을 재정의하는 환경 변수입니다 ( 일부 상황에서는 제외$LANGUAGE ).

지역화의 다양한 측면 (예 : 천 단위 구분 기호 또는 소수점 문자, 문자 집합, 정렬 순서, 월, 요일 이름, 오류 메시지와 같은 언어 또는 응용 프로그램 메시지, 통화 기호)은 몇 가지 환경 변수를 사용하여 설정할 수 있습니다.

일반적으로 $LANG지역을 식별하는 값으로 선호도를 설정 합니다 (예 : fr_CH.UTF-8프랑스어를 사용하는 스위스 인 경우 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 로케일에서 문자는 단일 바이트이고 문자 세트는 ASCII입니다 (잘, 필수는 아니지만 실제로는 대부분의 시스템에서 사용됩니다), 정렬 순서는 바이트 값을 기반으로합니다. 언어는 일반적으로 미국 영어 (응용 프로그램 메시지의 경우 (월 또는 일 이름 또는 시스템 라이브러리의 메시지와 달리), 응용 프로그램 작성자의 재량에 따름) 통화 기호와 같은 것은 정의되지 않습니다.

일부 시스템에서는 POSIX 로케일과 차이가 있는데, 예를 들어 비 ASCII 문자의 정렬 순서가 정의되어 있지 않습니다.

일반적으로 LC_ALL = C로 명령을 실행하여 사용자 설정이 스크립트를 방해하지 않도록합니다. 예를 들어 [a-z]26 개의 ASCII 문자를에서 a로 일치 시키 려면 z을 설정해야합니다 LC_ALL=C.

GNU 시스템에 LC_ALL=CLC_ALL=POSIX(또는 LC_MESSAGES=C|POSIX) 재정 $LANGUAGE,있는 동안은 LC_ALL=anything-else하지 않을 것입니다.

일반적으로 설정해야하는 몇 가지 경우 LC_ALL=C:

  • sort -u또는 sort ... | uniq.... C 이외의 많은 로케일에서 일부 시스템 (특히 GNU 시스템)에서는 일부 문자의 정렬 순서가 동일합니다 . sort -u고유 한 행을보고하지 않지만 정렬 순서가 동일한 각 행 그룹 중 하나를보고합니다. 따라서 고유 한 줄을 원하면 문자가 바이트이고 모든 문자가 다른 정렬 순서를 갖는 C로케일 이 필요합니다 ( 로케일이 보장합니다).
  • 동일한 것을 적용 =운영자 POSIX 호환 expr또는 ==POSIX 규격의 조작자 awk들 ( mawkgawk두 개의 스트링이 동일한 지 확인하지만 그들은 동일한 정렬 여부를하지 않는 점에서 POSIX되지 않는다).
  • 와 같은 문자 범위 grep. 사용자 언어로 된 글자를 일치 시키려면를 사용 grep '[[:alpha:]]'하고 수정하지 마십시오 LC_ALL. 그러나 a-zA-ZASCII 문자 를 일치 시키려면 LC_ALL=C grep '[[:alpha:]]'또는 LC_ALL=C grep '[a-zA-Z]'¹ 이 필요합니다 . 많은 API를 사용하면 그보다 더 복잡하지만 이전과 [a-z]이후에 정렬되는 문자와 일치합니다 . 다른 로케일에서는 일반적으로 이것이 무엇인지 모릅니다. 예를 들어 일부 로케일 그렇게 정렬하는 경우를 무시 과 같은 몇 가지의 API에 포함 할 수있다, 패턴 또는 . 많은 UTF-8 로켈에서 (를 포함하여 대부분의 시스템에서), 라틴어에서 편지가 포함됩니다 에 분음 부호하지만의 사람들을 (이후az[a-z]bash[B-Z][A-Y]en_US.UTF-8[a-z]ayzz내가 상상할 수없는 것들은 당신이 원하는 것입니다 (왜 포함 é하고 싶 ź습니까?).
  • 의 부동 소수점 산술 ksh93. ksh93decimal_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 로켈에서하고있어 입력이 ISO8859-15 같은 한 싱글 바이트 8 비트 문자로 인코딩 된 경우 어떤 작업. 때문 .만은 문자 및 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)과 대소 문자 변환 ( awktoupper(), dd conv=ucase...). 예를 들어 :

    grep -i i
    

    I사용자의 로캘에서 일치하지 않을 수 있습니다. 예를 들어 일부 터키어 로케일에서는 대문자 i가 있고 İ(점 참고) 소문자 Iı없습니다 (누락 된 점 참고).


¹ 텍스트 인코딩에 따라 반드시 옳은 것은 아닙니다. UTF-8 또는 1 바이트 문자 세트 (예 : iso-8859-1)에 유효하지만 반드시 UTF-8이 아닌 멀티 바이트 문자 세트는 아닙니다.

예를 들어, zh_HK.big5hkscs로케일 (홍콩, BIG5 한자 인코딩의 홍콩 변형을 사용하는)에 있고 해당 문자 세트로 인코딩 된 파일에서 영어 문자를 찾으려면 다음 중 하나를 수행하십시오.

LC_ALL=C grep '[[:alpha:]]'

또는

LC_ALL=C grep '[a-zA-Z]'

그 문자 세트 (및 다른 많은 문자이지만 UTF-8이 나온 이후 거의 사용되지 않기 때문에)에는 많은 문자 에 A-Za-z 문자의 ASCII 인코딩에 해당하는 바이트가 포함되어 있기 때문에 잘못되었습니다 . 예를 들어, 모든 A䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽(및 그 이상)에는의 인코딩이 포함되어 있습니다 A. ASCII에서와 같이 0x96 0x41 A이며 0x41입니다. 따라서 LC_ALL=C grep '[a-zA-Z]'바이트 시퀀스를 잘못 해석 할 수 있으므로 해당 문자가 포함 된 행에서 일치합니다.

LC_COLLATE=C grep '[A-Za-z]'

LC_ALL그렇지 않으면 설정되지 않은 경우에만 작동 합니다 (재정의 됨 LC_COLLATE). 따라서 다음을 수행해야 할 수도 있습니다.

grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'

로케일 인코딩으로 인코딩 된 파일에서 영어 문자를 찾으려면


12
+1, 재정의 등을 지적하는 것이 가장 좋습니다. 그러나 Ignacio의 답변에 대한 좋은 예가 없습니다 ^^
Olivier Dulac

1
작은 nitpick : C로케일은 "휴대용 문자 세트"(ASCII 0-127) 만 지원해야하며 문자> 127의 동작 은 기술적으로 지정되지 않습니다 . 실제로 대부분의 프로그램은이를 불투명 한 데이터로 취급하고 설명 된대로 전달합니다. 그러나 전부는 아닙니다. 특히 C로켈 에서 실행되는 경우 Ruby는 바이트가 127보다 큰 char 데이터를 질식시킬 수 있습니다 . 나는 그것이 기술적으로 "적합한"것인지 솔직히 모르겠지만, 우리는 그것을 야생에서 보았습니다 .
Andrew Janke

2
@AndrewJanke, 그렇습니다. 이식 가능한 문자 집합은 ASCII 나 0-127을 의미하지 않습니다. Austin 그룹 메일 링리스트에서 "C"로케일 문자 세트의 속성이 무엇인지에 대한 많은 논의가 있었으며 일반적인 합의는 (다음 스펙에서 명확해질 것입니다.) 바이트이며 전체 8 비트 범위 (여기에 설명 된 속성 포함)를 포함합니다. 그 사이에 버그가 있거나 사양이 명확하지 않기 때문에 약간의 차이가있을 수 있습니다. 어쨌든 LC_ALL = C는 제정신의 행동을 얻을 수있는 가장 가까운 것입니다.
Stéphane Chazelas

1
UTF-8의 유니 코드 코드 포인트는 최대 4 옥텟 (또는 바이트)을 가질 수 있지만 일부 문자는 하나 이상의 코드 포인트를 필요로하므로 6 옥텟보다 긴 시퀀스로 이어질 수 있습니다.
12431234123412341234123

1
@ 12,431,234,123,412,341,234,123 원래 UTF-8 인코딩 U + 7FFFFFFF까지 커버 (6 바이트와 같은 13 바이트까지가는 어떤 정보가있는 perlS '는 \x{7FFFFFFFFFFFFFFF}유니 코드 코드 포인트 범위가 임의로 U + 10FFFF 제한되었지만) 및 (UTF-16 디자인 제한으로 인해) 일부 도구는 여전히 6 바이트 문자를 인식 / 생성합니다. 이것이 6 바이트 문자의 의미입니다. 유닉스 의미론에서, 하나의 문자는 하나의 코드 포인트입니다. 귀하의 하나 개 이상의 코드 포인트 "문자는" 더 일반적으로 문자에서 명확하게하기 위해 graphem 클러스터로 참조됩니다.
Stéphane Chazelas

7

C기본 로케일이고 "POSIX"는 "C"의 별명입니다. "C"는 ANSI-C에서 파생 된 것 같습니다. 아마도 ANSI-C는 "POSIX"로케일을 정의 할 것입니다.


C와 UNIX는 ANSI C보다 훨씬 오래되었습니다.
CVn

@ MichaelKjörling : 그럼요? ANSI 이전의 문서를 보았는데 로캘이 없었습니다. AT & T Bell Labs에서는 내부적으로 영어를 사용했습니다.
MSalters

@MSalters C 언어에 대한 ANSI 사전 문서가 로케일을 언급하지 않는다는 사실 (ANSI 이전에 C에는 로케일 개념이 없음을 의미하거나 암시하지 않을 수도 있음) 결국 언어가 여전히 그렇지 않다고 확신합니다. 로 C케이트 이름이 "ANSI C"에서 파생 되었음을 의미하지는 않습니다 .
CVn

2
@ MichaelKjörling : 당신은 요점을 놓치고 있습니다. 로케일이 도입되었을 때 "C"는 이미 "ANSI C"를 의미했습니다. 그것은 과거에 K & R C가 무의미하다는 것을 의미했습니다.
MSalters

3

내가 알 수있는 한, OS X은 UTF-8 로켈에서 코드 포인트 조합 순서를 사용하므로 Stéphane Chazelas의 답변에 언급 된 일부 포인트는 예외입니다.

이것은 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에서 아무 것도 인쇄하지 않으며 동일한 조합 순서를 갖는 두 개의 연속 코드 포인트 (최소 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

(위의 예제 는 zsh에서 오류가 발생 하기 %b때문에 사용 printf \\U25합니다.)

GNU 시스템에서 데이터 정렬 순서가 동일한 일부 문자 및 문자 시퀀스는 OS X에서 동일한 데이터 정렬 순서를 갖지 않습니다. 이것은 OS X에서 첫 번째 (OS X sort또는 GNU 사용 sort)로 인쇄되지만 ② 우분투에서 첫 번째로 인쇄됩니다.

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

이것은 OS X에서 세 줄 (OS X sort또는 GNU 사용 sort)을 인쇄하지만 우분투에서 한 줄을 인쇄합니다.

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

왜 이런 차이가 있는지 아는 사람이 있습니까?
1.61803

3

LC_COLLATEls가 사용하는 "알파벳 순서" 를 제어하는 것으로 보입니다 . 미국 로케일은 다음과 같이 정렬됩니다.

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

기본적으로 기간을 무시합니다. 당신은 선호 할 것입니다 :

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

나는 확실히한다. 이것을 달성 LC_COLLATE하기 C위한 설정 . 또한 모든 대문자 뒤에 소문자를 정렬합니다.

A.C
A.H
AFilename.C
a.C
a.H
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.