LC_MESSSAGES를 적용하려면 macOS 홈브류 bash에서 내보내야 하는 이유는 무엇입니까?

LC_MESSSAGES를 적용하려면 macOS 홈브류 bash에서 내보내야 하는 이유는 무엇입니까?

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_*됩니다 . 의 경우 모든 변수를 다시 호출 합니다 . 의 경우 에는 효과가 없습니다.bashsetlocale()LANGsetlocale(LC_ALL, thevalue)setlocale(LC_*)LC_*LANGUAGE

이제 bashGNU 프로젝트의 쉘입니다. 텍스트 현지화 의 gettext경우 libintl.​bashconfigure--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자 메커니즘에 의해 수행된다는 것입니다.구현하다다른 명령의 경우 환경 변수를 사용하여 두 소프트웨어(여기 bashgettext) 간에 로케일 정보를 전달해야 합니다.

이제 GNU 시스템에서는 상황이 실제로 더 악화됩니다.

위에서 본 것처럼 gettext는 GNU libc에 포함되어 있습니다. $LANGUAGEPOSIX 로케일 API보다 선행 $LC_MESSAGE하지만 $LANGUAGE일부는 아니며 그 위에 있는 확장입니다.

setlocale(LC_MESSAGES, NULL)따라서 GNU 시스템에서는 LC_MESSAGES 카테고리의 이름을 가져오는 데 gettext가 사용됩니다. 왜냐하면 LC_MESSAGES LANGUAGE카테고리는 항상 로케일 카테고리가 아니라 getenv()사용 되기 때문입니다.LANGUAGE

문제는 bash변수 처리의 일부로 environ[]libc 배열과 연결이 끊어진 자체 환경을 관리한다는 것입니다. 자체적인 가 있고 getenv()자체 버전의 환경을 쿼리하지만 gettextlibc의 일부로 구축되고 bash동적으로 연결되면 dgettext()libc에서 호출됩니다. 이는 libc가 아닌 libc 내의 내부 호출이므로 그냥 시작 시간에서 값을 가져옵니다.getenv()bash$LANGUAGEbash

따라서 GNU 시스템에서는 정적으로 연결되거나 빌드를 사용하지 않는 한 생성된 메시지에 대한 모든 변경 사항은 bash변수 내보내기 여부에 관계없이 무시됩니다 . --with-included-gettext다른 시스템에서는 gettext가 libc의 일부가 아니므로 (내보내는 한) 괜찮습니다. 따라서 s를 호출합니다.$LANGUAGEbash$LANGUAGEbashgetenv()

데비안에서:

$ 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

쉘 변수는 쉘 전용이고 하위 프로세스로 전달되지 않으므로 로케일에 대한 환경 변수를 설정해야 합니다.

관련 정보