Правильное использование заглавных букв в сценариях Bash и shell

Я сталкивался со многими сценариями оболочки с переменными во всех заглавных буквах, и я всегда думал, что с этим есть серьезное недоразумение. Насколько я понимаю, что условно (и, возможно, по необходимости давно) переменные среды указаны в верхнем регистре.

Но в современных средах написания сценариев, таких как Bash, я всегда предпочитал использовать строчные имена для временных переменных, а заглавные только для экспортированных (то есть переменных среды). Например:

#!/usr/bin/env bash
year=`date +%Y`
echo "It is $year."
export JAVA_HOME="$HOME/java"

Это всегда был мой взгляд на вещи. Существуют ли авторитетные источники, которые либо соглашаются, либо не соглашаются с этим подходом, или это просто вопрос стиля?

10 ответов

Решение

По соглашению, переменные среды (PAGER, EDITOR,...) и внутренние переменные оболочки (SHELL, BASH_VERSION,...) пишутся с большой буквы. Все остальные имена переменных должны быть в нижнем регистре.

Помните, что имена переменных чувствительны к регистру; это соглашение позволяет избежать случайного переопределения внешних и внутренних переменных.

Соблюдая это соглашение, вы можете быть уверены, что вам не нужно знать каждую переменную среды, используемую инструментальными средствами или оболочками UNIX, чтобы избежать их перезаписи. Если это ваша переменная, то строчные. Если вы экспортируете его, используйте его в верхнем регистре.

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

  • Используйте все прописные и нижние подчеркивания для экспортируемых переменных и констант, особенно когда они используются несколькими сценариями или процессами. Используйте общий префикс, когда это применимо, чтобы связанные переменные выделялись и не конфликтовали с внутренними переменными Bash, которые все в верхнем регистре.

    Примеры:

    • Экспортируемые переменные с общим префиксом: JOB_HOMEJOB_LOGJOB_TEMPJOB_RUN_CONTROL
    • Константы: LOG_DEBUGLOG_INFOLOG_ERRORSTATUS_OKSTATUS_ERRORSTATUS_WARNING
  • Используйте "случай змеи" (все строчные и подчеркивания) для всех переменных, которые ограничены одним сценарием или блоком.

    Примеры: input_filefirst_valuemax_amountnum_errors

    Смешанный случай, когда локальная переменная имеет некоторую связь с переменной окружения, например: old_IFSold_HOME

  • Используйте начальное подчеркивание для "частных" переменных и функций. Это особенно актуально, если вы когда-либо пишете библиотеку оболочки, где функции внутри файла библиотеки или между файлами должны совместно использовать переменные, никогда не конфликтуя с чем-либо, что может быть названо аналогично в основном коде.

    Примеры: _debug_debug_level_current_log_file

  • Избегайте случая верблюда. Это сведет к минимуму ошибки, вызванные опечатками. Помните, что переменные оболочки чувствительны к регистру.

    Примеры: inputArraythisLooksBAD, numRecordsProcessed, veryInconsistent_style


Смотрите также:

Если переменные оболочки будут экспортированы в среду, стоит учесть, что в определении переменной среды POSIX (выпуск 7, выпуск 2018) указано:

Имена переменных среды, используемые утилитами в томе Shell и Utilities POSIX.1-2017, состоят исключительно из заглавных букв, цифр и символа подчеркивания (_) из символов, определенных в Portable Character Set, и не начинаются с цифры.

...

Пространство имен имен переменных среды, содержащих строчные буквы, зарезервировано для приложений. Приложения могут определять любые переменные среды с именами из этого пространства имен без изменения поведения стандартных утилит.

Я делаю то, что ты делаешь. Я сомневаюсь, что есть авторитетный источник, но де-факто это довольно распространенный стандарт.

На самом деле, термин "переменные среды", кажется, имеет довольно недавнюю чеканку. Керниган и Пайк в своей классической книге "Среда программирования UNIX", опубликованной в 1984 году, говорят только о "переменных оболочки" - в индексе даже нет записи о "среде"!

Давайте внесем ясность в нашу терминологию. Переменные среды — это переменные, заданные средой Bash (например, ${0}, ${SHELL}, ${SECONDS} и т. д.), которые не нужно задавать пользователю. Пользовательские переменные (и константы) устанавливаются пользователем либо в их .bash_profile, .bash_rc, либо в конкретном файле сценария. Пользовательские переменные можно экспортировать в среду, чтобы они стали переменными среды; однако, если она не экспортирована, область действия переменной User ограничена текущим выполнением интерпретатора (либо средой оболочки, либо исполняемым сценарием оболочки [т.е. не будет передана ни в одну дочернюю] среду). Если переменная среды не установлена ​​или сброшена, она обычно теряет какое-либо особое значение или значение.

За более чем 30 лет написания сценариев оболочки, выполнения сборок и выпусков и некоторого системного администрирования я видел все вышеупомянутые стили переменных. Unix допускает имена переменных, состоящие из малых и маленьких символов или любого сочетания этих двух наборов. Linux принял эту же мерзость по какой-то неизвестной причине, вероятно, из-за переносимости. Posix настоятельно рекомендует использовать набор символов majuscule, как и почти все тексты по программированию на Bash. Я пришел к выводу, что это соглашение широко распространено и используется, но не является строго обязательным, и вы вольны сделать любой неправильный выбор, какой пожелаете.

Тем не менее, существуют некоторые соглашения, которые используются из-за их полезности и потому, что они помогают программистам эффективно и результативно разрабатывать полезный и поддерживаемый код. Когда я пишу bash-код:

  1. Я использую символы маюскула и символы «_» для всех имен переменных и констант.

  2. Я набираю (так называемое определение) и инициализирую все переменные (и константы) и указываю тип переменной (целочисленный, только для чтения, экспортируемый, массив, хэш и т. д.), который является локальным для скриптов и функций (нет, все не обязательно должно быть глобальным). в Баше).

  3. Я использую символы '{' и '}' вокруг всех переменных (синтаксически обязательных или нет, чтобы избежать непреднамеренных ошибок в именах, которые я видел на практике) и выделяю переменную/константу.

  4. Сейчас я всегда использую «#!/usr/bin/env bash», а раньше всегда использовал «#!/usr/bin/bash» в системах, где «/usr/bin/env» был недоступен.

  5. Я использую «shop -s extglob # Включить расширенные глобальные выражения» в своих сценариях, потому что это очень удобно, когда я выполняю регулярные выражения и сопоставление с образцом.

  6. Я всегда использую «set -o Pipefail -o nounset -o errtrace -o functrace», чтобы избежать проблем с сбоями каналов в середине, жирной переборкой имен переменных и простотой отслеживания ошибок и функций. Я знаю других, которые часто используют «shopt -s inherit_errexit nullglob compat», и я также вижу полезность этих опций.

  7. Все сообщения об ошибках, которые я распечатываю, следуют шаблону, который позволит программисту узнать, где в коде была обнаружена ошибка и о которой было сообщено.echo -e "ОШИБКА [${LINENO}] в ${FUNCNAME[*]}: ..." 1>&2

Последовательное использование общепринятых соглашений и передовых методов программирования может значительно сократить время отладки и сделать ваш код легко переносимым и поддерживаемым. Например, Bash не требует определения и инициализации переменных, но может предотвратить использование неинициализированных значений и позволяет пользователям писать более качественный код и обнаруживать имена значений с ошибками.

Работая над кодом, который использует все крошечные символы для переменных и констант, мой опыт показывает, что такая практика очень затрудняет четкое представление о том, где используется переменная, и позволяет очень легко совершать ошибки.

Я использую верблюжий регистр в именах функций (личное предпочтение, а не соглашение). Это дает понять, что я вызываю локальную функцию, которую я создал или передал в среду.

Наконец, я рекомендую использовать команду «source» вместо старой «.». символ при получении кода из другого файла. По крайней мере, с помощью этой опции гораздо проще найти все места, где я что-то покупаю.

За свою карьеру я приобрел множество навыков, гораздо больше, чем имеет отношение к этой теме (да, я зашел далеко), но Bash — невероятно полезный и вездесущий инструмент программирования для *nix-систем. Научиться писать понятный и удобный в сопровождении код, следуя общепринятым соглашениям, является признаком профессионального роста.

Это просто очень широко распространенное соглашение, я сомневаюсь, что есть какой-либо "авторитетный" источник для него.

Я склонен использовать ALL_CAPS как для окружающей среды, так и для глобальных переменных. конечно, в Bash нет реальной области видимости переменных, поэтому есть хорошая часть переменных, используемых в качестве глобальных переменных (в основном это настройки и отслеживание состояния), и относительно немного "локальных" (счетчики, итераторы, частично построенные строки и временные переменные)

Bash и большинство интерпретаторов сценариев оболочки распознают глобальные и локальные переменные внутри функций (например, typeset, declare, local) и должны использоваться соответствующим образом. Как отмечалось ранее, «Имена переменных среды, используемые утилитами в томе Shell и Utilities в POSIX.1-2017, состоят исключительно из прописных букв, цифр и подчеркивания (_) из символов, определенных в переносимом наборе символов, и не начинаются с цифрой. ... Пространство имен переменных среды, содержащих строчные буквы, зарезервировано для приложений. Приложения могут определять любые переменные среды с именами из этого пространства имен без изменения поведения стандартных утилит. " ( POSIX IEEE Std 1003.1-2008 раздел 8.1 )

ALL_CAP СЛИШКОМ УРОДЕН, ЧТОБЫ БЫСТРО УЗНАВАТЬ !!!!!!!!!!!!!!!!!!!!!

ссылка: https://uxmovement.com/content/all-caps-hard-for-users-to-read

для моей собственной конфигурации я использую все, что хочу:

        export XDG_CONFIG_HOME=$( realpath "$HOME/.config" )                                                                                                                                           
  export XDG_CACHE_HOME=$( realpath "$HOME/d/.cache_wf" )
  export XDG_DATA_HOME=$( realpath "$HOME/.local/share" )

  # 全部大写, 难辨认, 用这个:
  export cfg_X=$XDG_CONFIG_HOME
  export cache_X=$XDG_CACHE_HOME
  export data_X=$XDG_DATA_HOME

  [ -d "$cfg_X" ] || mkdir -m 0750 -p "$cfg_X"
  [ -d "$cache_X" ]  || mkdir -m 0750 -p "$cache_X"
  [ -d "$data_X" ]   || mkdir -m 0750 -p "$data_X"

(И я предпочитаю скриншот вставленному тексту из-за цвета и формата)

Другие вопросы по тегам