Создание переиспользуемых шаблонов Bash-скриптов для эффективности
Создавайте переиспользуемые шаблоны Bash-скриптов со строгим режимом, текстом использования, логированием, очисткой и безопасным разбором аргументов с помощью getopts.
Создание переиспользуемых шаблонов Bash-скриптов для эффективности
Переиспользуемые шаблоны Bash-скриптов помогают перестать переписывать одни и те же проверки безопасности каждый раз, когда вы автоматизируете задачу. Хороший шаблон предоставляет вашему скрипту строгую обработку ошибок, предсказуемое логирование, справку по использованию, разбор аргументов и хуки для очистки до того, как вы добавите специфичную для проекта логику.
Цель — не огромный фреймворк. Это небольшая отправная точка, которая делает рутинные скрипты согласованными и более простыми в отладке.
Зачем использовать шаблоны скриптов?
Шаблоны полезны, когда ваша команда пишет много небольших скриптов для резервного копирования, развертывания, отчетов, очистки логов или перемещения данных. Без шаблона каждый скрипт, как правило, обрабатывает ошибки, опции и логирование немного по-своему.
Переиспользуемый шаблон дает вам:
- Согласованный строгий режим и привычки использования кавычек.
- Стандартную функцию
usage. - Единое место для вспомогательных функций логирования.
- Хук для очистки временных файлов и блокировок.
- Предсказуемый разбор командной строки с помощью
getopts.
Основные части шаблона
Начните с самого Bash, затем включите строгое поведение:
#!/usr/bin/env bash
set -euo pipefail
set -e завершает скрипт при многих необработанных сбоях команд, set -u считает неопределенные переменные ошибками, а set -o pipefail перехватывает сбои внутри конвейеров. Вам все еще нужны явные проверки для ожидаемых сбоев, но строгий режим перехватывает многие случайные ошибки.
Добавьте имя скрипта и короткий блок использования:
readonly SCRIPT_NAME="$(basename "$0")"
usage() {
cat <<USAGE
Использование: $SCRIPT_NAME [-v] [-o выходная_директория] входной_файл
Опции:
-v Включить подробное логирование
-o выходная_директория Записать вывод в эту директорию
-h Показать это справочное сообщение
USAGE
}
Используйте небольшие вспомогательные функции для логирования вместо разрозненных вызовов echo:
log_info() {
[[ "$VERBOSE" -eq 1 ]] && printf '[INFO] %s\n' "$1"
}
die() {
printf '[ERROR] %s\n' "$1" >&2
exit 1
}
Если скрипт создает временные файлы или файлы блокировки, добавьте функцию очистки заранее:
cleanup() {
# Удалить временные файлы или снять блокировки здесь.
:
}
trap cleanup EXIT
Безопасный разбор аргументов с помощью getopts
Большинству переиспользуемых шаблонов нужны флаги. Встроенного getopts в Bash достаточно для коротких опций, таких как -v и -o выходная_директория.
VERBOSE=0
OUTPUT_DIR="."
while getopts ":vo:h" opt; do
case "$opt" in
v) VERBOSE=1 ;;
o) OUTPUT_DIR=$OPTARG ;;
h) usage; exit 0 ;;
:) die "Опция -$OPTARG требует аргумент" ;;
\?) die "Неизвестная опция: -$OPTARG" ;;
esac
done
shift "$((OPTIND - 1))"
INPUT_FILE=${1:-}
[[ -n "$INPUT_FILE" ]] || { usage >&2; exit 1; }
[[ -f "$INPUT_FILE" ]] || die "Входной файл не найден: $INPUT_FILE"
Начальное : в ":vo:h" позволяет вашему скрипту самостоятельно обрабатывать отсутствующие аргументы опций. После разбора shift "$((OPTIND - 1))" удаляет разобранные опции, чтобы позиционные аргументы было легче читать.
Компактный шаблон для повторного использования
Вот практическая отправная точка для небольших операционных скриптов:
#!/usr/bin/env bash
set -euo pipefail
readonly SCRIPT_NAME="$(basename "$0")"
VERBOSE=0
OUTPUT_DIR="."
usage() {
cat <<USAGE
Использование: $SCRIPT_NAME [-v] [-o выходная_директория] входной_файл
USAGE
}
log_info() {
[[ "$VERBOSE" -eq 1 ]] && printf '[INFO] %s\n' "$1"
}
die() {
printf '[ERROR] %s\n' "$1" >&2
exit 1
}
cleanup() {
:
}
trap cleanup EXIT
while getopts ":vo:h" opt; do
case "$opt" in
v) VERBOSE=1 ;;
o) OUTPUT_DIR=$OPTARG ;;
h) usage; exit 0 ;;
:) die "Опция -$OPTARG требует аргумент" ;;
\?) die "Неизвестная опция: -$OPTARG" ;;
esac
done
shift "$((OPTIND - 1))"
INPUT_FILE=${1:-}
[[ -n "$INPUT_FILE" ]] || { usage >&2; exit 1; }
[[ -f "$INPUT_FILE" ]] || die "Входной файл не найден: $INPUT_FILE"
mkdir -p "$OUTPUT_DIR"
log_info "Обработка $INPUT_FILE"
# Добавьте логику вашего скрипта здесь.
Держите шаблон коротким. Добавляйте общие функции только тогда, когда они действительно нужны нескольким скриптам. Шаблон должен устранять повторяющуюся работу по настройке, а не делать каждый скрипт похожим на фреймворк.