10 функций, которые помогут сделать bash-скрипты чуть более элегантными
1. log()
: простой логгер с метками времени
log() { local level="$1"; shift local timestamp timestamp=$(date "+%Y-%m-%d %H:%M:%S") echo "[$timestamp] [$level] $*" >&2 }
Эта функция выводит все логи в одном формате — с меткой времени и уровнем логирования (INFO, ERROR и т.д.). Очень удобно и для отладки, и для продакшн-логов.
Пример:
log "INFO" "Deployment started" log "ERROR" "Failed to connect to the database"
2. retry()
: повтор команды с экспоненциальной задержкой
retry() { local retries="$1"; shift local count=0 exit_code=0 until "$@"; do exit_code=$? ((count++)) if ((count >= retries)); then log "ERROR" "Command failed after $retries attempts: $*" return "$exit_code" fi log "WARN" "Retrying ($count/$retries)..." sleep $((count * 2)) done }
Незаменима при работе с ненадёжными сервисами (например, HTTP API), которые иногда могут отвалиться. С этой функцией ваш скрипт станет гораздо устойчивее к таким сбоям.
Пример:
retry 5 curl -sf http://localhost:8080/healthz
3. check_required_env()
: проверка обязательных переменных окружения
check_required_env() { for var in "$@"; do if [[ -z "${!var:-}" |]]; then log "ERROR" "Missing required environment variable: $var" exit 1 fi done }
Позволяет сразу же завершить выполнение скрипта, если чего-то важного не хватает — например, секретного ключа или конфигурационного параметра.
Пример:
check_required_env AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY
4. load_config()
: загрузка .env
-файлов или конфигов в формате ключ-значение
load_config() { local config_file="$1" [[ -f "$config_file" |]] || { log "ERROR" "Config file not found: $config_file"; return 1; } while IFS='=' read -r key value || [[ -n "$key" |]]; do [[ "$key" =~ ^\s*# |]] || [[ -z "$key" |]] && continue key=$(echo "$key" | xargs) value=$(echo "$value" | sed 's/^"\(.*\)"$/\1/' | xargs) export "$key=$value" done < "$config_file" }
Позволяет выносить конфигурацию за пределы скрипта — по канонам 12-factor приложений. Можно грузить .env
или любой файл с переменными в формате KEY=VALUE
.
Пример:
load_config "./myapp.env"
5. safe_rm()
: перемещает в корзину вместо удаления
safe_rm() { local file="$1" [[ -e "$file" |]] || { log "WARN" "File not found: $file"; return 1; } local trash_dir="$HOME/.trash" mkdir -p "$trash_dir" local base base=$(basename "$file") local timestamp timestamp=$(date +%s) mv "$file" "$trash_dir/${base}_${timestamp}_$$" && \ log "INFO" "Moved $file to trash instead of deleting" }
Полезно в ситуациях, когда скрипт делает что-то потенциально разрушительное. Вместо удаления — просто перемещает файл в «корзину».
Пример:
safe_rm "config.yml"
6. confirm()
: запрос подтверждения (Yes/No)
confirm() { local prompt="${1:-Are you sure?} (y/n): " while true; do read -rn 1 -p "$prompt" response echo case "${response,,}" in y) return 0 ;; n) return 1 ;; *) echo "Please enter y or n." ;; esac done }
Добавляет защиту от случайного запуска опасных операций. Простое «уверены ли вы?» перед тем, как что-то пойдёт не так.
Пример:
if confirm "Are you sure you want to delete production DB?"; then delete_database fi
7. monitor_usage(): быстрая проверка CPU и памяти
monitor_usage() { echo "CPU: $(top -bn1 | grep 'Cpu(s)' | awk '{print $2 + $4}')%" echo "Memory: $(free -m | awk '/Mem:/ { printf("%.2f%%", $3/$2 * 100.0) }')" }
Простой способ быстро проверить состояние системы — особенно полезно перед деплоем или сразу после него.
Лучше всего работает на Linux. На macOS может не сработать без установки аналогов top
и free
.
8. require_command()
: проверка, что нужные утилиты установлены
require_command() { for cmd in "$@"; do if ! command -v "$cmd" &>/dev/null; then log "ERROR" "Missing required command: $cmd" exit 1 fi done }
Скрипт сразу падает, если не хватает нужных CLI-инструментов — например, jq
, curl
или aws
.
Пример:
require_command jq docker aws
9. wrap_with_timer()
: измеряет время выполнения команды
wrap_with_timer() { local start end elapsed start=$(date +%s) "$@" local exit_code=$? end=$(date +%s) elapsed=$((end - start)) log "INFO" "Command '$*' completed in ${elapsed}s" return $exit_code }
Помогает отслеживать производительность и находить узкие места.
Пример:
wrap_with_timer run_long_script
10. cleanup()
: удаляет временные файлы при выходе
cleanup() { log "INFO" "Cleaning up..." rm -f /tmp/my-temp-file } trap cleanup EXIT
Чтобы скрипт не оставлял за собой мусор (например, временные файлы или lock-файлы), даже если завершился с ошибкой.
Бонус: шаблон скрипта с использованием всех этих функций
#!/usr/bin/env bash set -euo pipefail # Import shared functions source ./functions.sh # Ensure required commands and environment require_command jq curl docker check_required_env ENVIRONMENT # Load environment-specific configuration load_config "./.env.${ENVIRONMENT}" # Begin script log "INFO" "Starting automation for $ENVIRONMENT" wrap_with_timer deploy_application