Стиль и удобочитаемость bash скриптов

Удобочитаемость

Код пишется один раз, а читать придется много раз удобочитаемость имеет огромное значение.

  • Не старайся быть “умным”, старайся быть ясным
  • Только понятные и говорящие имена переменных, избегай абстрактных и общих понятий
  • Справка (по -h/—help) в скриптах нужна
  • Юзай source, а не ”.”, ибо точку сложнее найти
  • По возможности юзай даты в формате ISO-8601 (Полный синтаксис: 2011-08-12T20:17:46.384Z). Это международный формат.
  • Упорядочивай элементы списков: например, IP-адреса, имена хостов, пакеты для установки, операторы case, содержимое переменных или массивов/списков. Это упростит добавление/удаление элементов.
  • Юзай длинные ключи команд (diff --quiet вместо diff -q) - такой код понятнее даже без комментов. Документируй свой выбор: почему взят именно этот ключ и даже почему не подходят другие ключи. Если у команды нет длинных ключей - поясняй комментами короткие. Документируй проблемные ключи, которые часто тянет заюзать.

Соус: Книга “Идиомы Bash Глава 11. “Разработка своего руководства по стилюУдобочитаемость

Комменты

  • Комменты пиши с заглавной буквы и юзай пунктуацию только если комментарий не состоит из нескольких предложений.
  • Юзай заголовки к командам (да и вообще ко всему).
  • Комменты должны объяснять: ПОЧЕМУ что-то делается/не делается, а неЧТО делается”, ибо если ты и так пишешь понятный код - такие простые комменты ни к чему. Исключение - непонятные не знакомым с bash идиомы (здесь стоит объяснить, что делает идиома). Хорошо, когда комменты поясняют, почему ты поступил именно так и каковы твои намерения.
  • Комментируй ключи

Логические блоки кода полезно выделять разделителями. Но добавлять рамки снизу и справа НЕ НАДО - потом будет дрочь обновлять содержимое внутри рамки, сдвигая рамки снизу и справа…🤢. Делай такие рамки:

#############################################################
# Оформляй рамки так 
#
# Если понадобиться добавить что-то
# просто надо будет добавить # на следующей строке
# ...

Соус: Книга “Идиомы Bash Глава 11. “Разработка своего руководства по стилюКомментарии

Имена

Повторятся про говорящие имена не буду.

  • Имена глобальных переменных и констант пиши ЗАГЛАВНЫМИ буквами, другие переменные - строчными.
    • Старайся не изменять глобальные переменные, если это возможно (хотя иногда это упрощает код (KISS))
    • Объявляй константы с помощью readonly или declare -r
  • Имена функций Смешанным_Регистром
  • Не юзай ВерблюжийРегистр
  • Не юзай дефис (-) в именах переменных
  • Не сокращай имена
  • Минимально юзай массивы bash - сложно читаются. Проще всего юзать for var in $regular_var
  • Вместо directly использования позиционных параметров ($1, $2…) присваивай их значения в начале переменным с говорящими именами.
  • Различай типы ссылок: $input_file и $input_dir
  • Юзай метки FIXME и TODO (с именами и номерами заявок, если это уместно).

Соус: Книга “Идиомы Bash Глава 11. “Разработка своего руководства по стилюИмена

Функции

  • Юзай заголовки к функциям, представляющие их
  • Функции определяются ДО их использования
    • Функции лучше группировать в начале скрипта и отделять друг от друга w/ 2 blank lines.
    • Не размещай между функциями иной код
  • Юзай function Some_Func вместо Some_Func (), ибо первый вариант понятнее и его проще найти потом
  • Each функция должна содержать комменты, поясняющие:
    1. Что она делает
    2. Какие данные принимает (включая глобальные)
    3. Какие данные выводит/возвращает
  • Повторяющиеся блоки кода оборачивай в функции, а те, которые востребованы в других скриптах (например, логирование, отправка почты) - в библиотеку-файл, чтобы потом source-ить их в других скриптах.
    • Пиши имена “библиотечных” функций с одинаковым префиксом (например, подчеркивание (_) - _Log)
  • Юзай local переменные, если нет нужны в глобальных. Имей в виду, что local переменные маскируют неудачный код возврата, поэтому объявляй и инициализируй их в отдельных строках, используя подстановку команд. Например, сначала local var и уже потом var="$(some_cmd)"
  • Длинные функции с кодом больше 25 строк закрывай комментарием } # Конец фунции Some_Func, чтобы легче было находить конец функции. Да и для коротких функций такие комменты не будут лишними.
  • В большинстве случаев функция main не нужна. Это имеет смысл в Python/C, где код может использоваться (также) в качестве библиотеки, + такая функция нужна для модульного тестирования
  • Отделяй основной код от блока с функциями w/ 2 blank lines и разделительным комментом, особенно если функций много.
  • Сделай в своей библиотеке функцию для логирования (например, _Log), чтобы, как минимум, унифицировать ее использование во всех скриптах. В идеале, лучше юзать логирование в syslog (особенно в “системных” скриптах), чтобы позволить ОС самой разобраться, куда логировать и т.п.

Можешь юзать заполнители в функциях, по типу:

local junk1="$2"  # Неиспользуемый заполнитель

Похоже на:

if <условие> then
	: # Ничего не делает и передает управление далее
else
	some_actions
fi

Соус: Книга “Идиомы Bash Глава 11. “Разработка своего руководства по стилюФункции

Кавычки

  • Бери в кавычки переменные и строки, чтобы явно пояснять свои намерения/мотивы (только если эти кавычки не загромождают код).
  • Бери в кавычки подстановку команд
  • Бери в кавычки обе части выражения любого оператора проверки, например [[ "$foo" == 'bar' ]]. Исключения:
    • Целое число
    • Если используется ~=, потому что RegEx нельзя брать в кавычки
  • Бери в одинарные кавычки переменные внутри строк, чтобы легче было найти их: echo "some '$text' w/ othuh shit". Но лучше, по мне, брать в [ ]: echo "some [$text] w/ othuh shit". Так получишь ошибку, если переменная была undefined.
  • Юзай одинарные кавычки, если не нужна интерполяция
  • Юзай одинарные кавычки в printf
  • Не бери в кавычки целые числа
  • Не юзай без необходимости ${var} конструкцию

Соус: Книга “Идиомы Bash Глава 11. “Разработка своего руководства по стилюКавычки

Форматирование

  • Не забудь про отступы, хоть они и не имеют значения в bash
  • Не оставляй пробелов в конце строк. Для git, к примеру, это вызовет лишний шум.
  • Длинные строки переноси на 78-м знаке (включая пробелы) и в next строке - отступ на два пробела.
  • Разрывай строки ПЕРЕД символом | или >, чтобы в начале строк они были заметны
cmd \
  | other_cmd \
  | yet_another_cmd
  • Код, открывающий блок, пиши в одну строку: if expr; then ... or for expr; do ...
  • В case однострочные элементы закрывай символами ;; в той же строке. Выравнивай отступы по ) в каждом элементе (если это не загромождает код).

Соус: Книга “Идиомы Bash Глава 11. “Разработка своего руководства по стилюФорматирование

Синтаксис

  • Всегда юзай $@, только если не уверен, что тебе реально нужен $*
  • Для проверки равенства юзай == вместо =, чтобы не путать с присваиванием.
  • Юзай [[ вместо [ , если только не нужен [ для переносимости (например, в bash).
  • Для integer арифметики юзай (( )) и $(( )) , а не let и expr
  • Избегай IFS=$'\n\t'

Соус: Книга “Идиомы Bash Глава 11. “Разработка своего руководства по стилюСинтаксис

bash