macOS에서는 homebrew에서 bash를 설치한 후 설정이 현재 셸의 로케일에 일부 영향을 미치는 것처럼 보였지만 메시지는 LC_MESSAGES
내보낼 때까지 실제로 변경되지 않았습니다.LC_MESSAGES
설정을 해제 LANG
하면 LC_MESSAGES
예상되는 오류 메시지가 영어로 표시됩니다.
bash-4.4$ unset LANG LC_MESSAGES
bash-4.4$ if :; fi
bash: syntax error near unexpected token `fi'
잘못된 값으로 설정하면 LC_MESSAGES
다음 오류가 발생합니다 setlocale
.
bash-4.4$ LC_MESSAGES=foo
bash: warning: setlocale: LC_MESSAGES: cannot change locale (foo): No such file or directory
그래서무엇내가 설정하면 변경됩니다 LC_MESSAGES
. 그러나 합리적인 값으로 설정해도 아무런 효과가 없습니다.
bash-4.4$ LC_MESSAGES=ja_JP.UTF-8
bash-4.4$ if :; fi
bash: syntax error near unexpected token `fi'
내보낼 때까지:
bash-4.4$ export LC_MESSAGES
bash-4.4$ if :; fi
bash: 予期しないトークン `fi' 周辺に構文エラーがあります
LANG
(모두 적용되는 것 같습니다.)
Bash 매뉴얼 섹션배쉬 변수LC_MESSAGES
내보내 거나 내보내야 하는 것은 없습니다 LANG
(그리고 여기에 나열된 대부분의 다른 변수는 내보낼 필요가 없습니다).
왜 이런거야?
답변1
당신 말이 맞습니다. 쉘 변수를 할당하면 내보내기 여부에 관계없이 해당 범주의 POSIX가 변수 값으로 호출 LC_*
됩니다 . 의 경우 모든 변수를 다시 호출 합니다 . 의 경우 에는 효과가 없습니다.bash
setlocale()
LANG
setlocale(LC_ALL, thevalue)
setlocale(LC_*)
LC_*
LANGUAGE
이제 bash
GNU 프로젝트의 쉘입니다. 텍스트 현지화 의 gettext
경우 libintl
.bash
configure
--with-included-gettext
gettext
각 언어에 대한 데이터베이스에서 메시지 번역을 찾아보세요. 어떤 언어인지는 카테고리 값에 따라 결정되지만 환경 변수에 의해 재정의 LC_MESSAGES
될 수 있습니다 .$LANGUAGE
gettext 문서에 따르면 이전 호출은 setlocale()
카테고리 값을 결정하는 호출이어야 하지만 몇 가지 복잡한 문제가 있습니다.
멀티스레드 애플리케이션의 경우,현재 이 값을 검색하는 데 사용할 수 있는 표준 API gettext가 없습니다.. bash
멀티스레드 애플리케이션은 아니지만 그것이 무엇인지조차setlocale(category, NULL)
반품은구현 정의실제로 항상 사용할 수 있는 것은 아닙니다..
따라서 실제로 gettext는 setlocale()
GNU libc의 일부로 빌드되거나 libc가 GNU libc인 시스템(예: GNU libc로 빌드된 시스템)에서 언어 bash
이름을 검색하는 데에만 사용됩니다. --with-included-gettext
.
getenv()
다른 시스템에서는 이전에 호출된 방식 에 관계없이 로케일을 결정하는 데 사용되므로 setlocale()
이러한 동작이 표시됩니다.
이러한 변수를 내보내는 것은 간단한 해결 방법입니다. 수출되지 않으면 환경의 일부가 아니라고 말할 수도 있습니다. POSIX는 이에 대해 명확하지 않습니다. 또 다른 관점에서는 번역이 에 의해 수행되는 것이 아니라 bash
제3자 메커니즘에 의해 수행된다는 것입니다.구현하다다른 명령의 경우 환경 변수를 사용하여 두 소프트웨어(여기 bash
및 gettext
) 간에 로케일 정보를 전달해야 합니다.
이제 GNU 시스템에서는 상황이 실제로 더 악화됩니다.
위에서 본 것처럼 gettext는 GNU libc에 포함되어 있습니다. $LANGUAGE
POSIX 로케일 API보다 선행 $LC_MESSAGE
하지만 $LANGUAGE
일부는 아니며 그 위에 있는 확장입니다.
setlocale(LC_MESSAGES, NULL)
따라서 GNU 시스템에서는 LC_MESSAGES 카테고리의 이름을 가져오는 데 gettext가 사용됩니다. 왜냐하면 LC_MESSAGES LANGUAGE
카테고리는 항상 로케일 카테고리가 아니라 getenv()
사용 되기 때문입니다.LANGUAGE
문제는 bash
변수 처리의 일부로 environ[]
libc 배열과 연결이 끊어진 자체 환경을 관리한다는 것입니다. 자체적인 가 있고 getenv()
자체 버전의 환경을 쿼리하지만 gettext
libc의 일부로 구축되고 bash
동적으로 연결되면 dgettext()
libc에서 호출됩니다. 이는 libc가 아닌 libc 내의 내부 호출이므로 그냥 시작 시간에서 값을 가져옵니다.getenv()
bash
$LANGUAGE
bash
따라서 GNU 시스템에서는 정적으로 연결되거나 빌드를 사용하지 않는 한 생성된 메시지에 대한 모든 변경 사항은 bash
변수 내보내기 여부에 관계없이 무시됩니다 . --with-included-gettext
다른 시스템에서는 gettext가 libc의 일부가 아니므로 (내보내는 한) 괜찮습니다. 따라서 s를 호출합니다.$LANGUAGE
bash
$LANGUAGE
bash
getenv()
데비안에서:
$ LANGUAGE=fr bash -c 'LANGUAGE=es; eval fi'
bash: eval: ligne 0: erreur de syntaxe près du symbole inattendu « fi »
bash: eval: ligne 0: `fi'
$LANGUAGE
( bash
스페인어가 아닌 프랑스어로 된 메시지, 당시 호출된 값).
사실 다른 껍데기에 비해 별로 좋지는 않습니다.
zsh
다른 언어로 번역되지는 않았지만 GNU 시스템에서 내부적으로 사용됩니다 strerror()
.gettext
$ LANGUAGE=fr zsh -c 'LANGUAGE=es; true</x; LANGUAGE=en; true</a; true < /etc/shadow'
zsh:1: no existe el archivo o el directorio: /x
zsh:1: no existe el archivo o el directorio: /a
zsh:1: permission denied: /etc/shadow
감사합니다 LANGUAGE=es
. 하지만 ENOENT에 대한 두 번째 메시지가 어떻게 영어로 표시되지 않는지 살펴보세요(어쨌든 gettext에 의해 캐시되었을 것입니다. 캐시는 $LANGUAGE
변경될 때 무효화되어야 했지만 그렇지 않았습니다).
답변2
보세요이 답변쉘 변수와 환경 변수의 차이점을 설명하십시오. 본질적으로:
셸 변수를 설정합니다.
LANG=en_US.UTF-8
환경 변수를 설정합니다.
export LANG=en_US.UTF-8
쉘 변수는 쉘 전용이고 하위 프로세스로 전달되지 않으므로 로케일에 대한 환경 변수를 설정해야 합니다.