Почему LC_MESSSAGES нужно экспортировать на macOS homebrew bash, чтобы это вступило в силу?

  • Проверьте, не открыт ли порт приложениями, когда вы хотите его использовать.

  • Проверьте, нет ли сообщений в журнале ядра (используйте dmesg).

  • Проверьте, что именно происходит в вашем приложении - запустите его под strace, который сообщит о системных вызовах, которые делает приложение. Возможно, вы захотите использовать что-то вроде:

    $ strace -f -s 512 -o /path/to/application.log.strace application ...
    

что также strace дочерние процессы, строки журнала ap до их 512-го байта и все это окажется в /path/to/application.log.strace, многоточие означает возможные аргументы для приложения. Вы также можете указать strace прикрепляться к запущенному процессу, идентифицированному PID (аргумент -p). Дополнительную информацию см. на странице strace(1). Ближе к концу журнала вы должны найти вызов write(), который печатает сообщение об ошибке. Есть шанс, что относительно незадолго до этого будет open() или write() (на файле устройства), который вернул -1. Это может дать вам некоторое представление о причине ошибки.

В качестве примечания относительно прав доступа: вы не хотите использовать chmod 777, поскольку это делает файл исполняемым, а это никогда не является хорошей идеей для чего-либо еще, кроме исполняемых файлов и каталогов. Для файлов устройств (в зависимости от их природы) разумными значениями являются 0640 или 0660, что позволяет полный доступ для root и доступ на чтение или чтение-запись для группы (членом которой должен быть данный пользователь, чтобы получить разрешения - в вашем случае это, вероятно, группа dialout, которую вы упомянули).

В большинстве случаев вы также хотите добавить ноль (например, chmod 0664, поскольку это удаляет любые биты suid, что обычно является хорошей идеей).

4
16.11.2018, 08:42
2 ответа

Вы правы в том, что назначение переменных оболочки LC_*заставляет bashвызывать POSIX setlocale()для соответствующей категории со значением переменной независимо от того, экспортируются они или нет. Для LANGон вызывает setlocale(LC_ALL, thevalue), а затем снова setlocale(LC_*)для всех переменных LC_*. Для LANGUAGEэто ничего не делает.

Итак, bash— это оболочка проекта GNU. Для локализации текста используется 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 (, например той, которая была собрана с помощью bashс --with-included-gettextв системе GNU ), потому что знает, что на нее можно положиться.

В других системах он использует getenv()для определения локали, независимо от того, как setlocale()был вызван ранее, поэтому вы видите такое поведение.

Экспорт этих переменных легко обойти. Можно возразить, что если они не экспортируются, то они все равно не являются частью окружающей среды.POSIX не очень ясен в этом. Другой способ взглянуть на это заключается в том, что перевод выполняется не bash, а сторонним механизмом, поэтому, как и при выполнении других команд, нам нужно использовать переменные среды для передачи информации о локали. между двумя программами (здесь bashиgettext).

Теперь, в системах GNU, все становится еще хуже.

Как показано выше, gettext включен в GNU libc. $LANGUAGEимеет приоритет над $LC_MESSAGE, но $LANGUAGEне является частью API локали POSIX, это расширение поверх него.

Таким образом, в системе GNU gettext будет использовать setlocale(LC_MESSAGES, NULL)для получения имени категории LC _MESSAGES, для LANGUAGEвсегда используется getenv(), LANGUAGEне является локалью.

Проблема в том, что bashуправляет средой сам по себе как часть своей обработки переменных, отключенной от массива environ[]libc. У него есть собственный getenv(), который запрашивает собственную версию среды, но когда gettextсоздается как часть libc и bashдинамически компонуется, dgettext()вызывает getenv()из libc как это внутренний вызов внутри libc, а не bash, поэтому будет получено значение $LANGUAGEтолько с момента запуска bash.

Таким образом, в системах GNU, если только bashне была связана статически или не была создана с помощью --with-included-gettext, любые изменения в $LANGUAGEбудут игнорироваться для сообщений, сгенерированных bash, вне зависимости от того, экспортирована переменная или нет. В других системах это нормально (, если $LANGUAGEэкспортируется ), так как gettext не является частью libc, поэтому он вызывает bash's getenv().

В Debian:

$ 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не переведен на другие языки, но использует strerror(), который использует gettextвнутри систем GNU:

$ 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
27.01.2020, 20:59

Взгляните на этот ответ для объяснения разницы между переменной оболочки и переменной окружения. По существу:

Установка переменной оболочки:

LANG=en_US.UTF-8

Установка переменной окружения:

export LANG=en_US.UTF-8

Вы хотите установить переменные среды для локали, поскольку переменные оболочки являются частными для оболочки и не будут передаваться дочерним процессам.

0
27.01.2020, 20:59

Теги

Похожие вопросы