Собственно, сам список сниппетов:
Сниппет №1 - шебанг и базовые переменные скрипта
1#!/usr/bin/env bash
2# Шебанг: запускает bash, найденный через env - более переносимо, чем /bin/bash
3
4# Параметры безопасности (повышает надёжность и предсказуемость скрипта)
5set -Eeuo pipefail
6# -e - выход при ошибке
7# -E - trap ERR работает в функциях/subshell
8# -u - ошибка при обращении к неустановленной переменной
9# -o pipefail - конвейер завершается при ошибке любой команды
10
11# Явное определение PATH
12# Исключает зависимость от окружения и защищает от подмены команд
13export PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
14
15# Базовые переменные
16SCRIPT_PID=$$ # PID скрипта, полезно для логов и уникальных файлов
17# Абсолютный путь к каталогу скрипта (без симлинков)
18SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P)
19SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")" # Имя файла скрипта
20SCRIPT_LOG="${SCRIPT_DIR}/${SCRIPT_NAME%.*}.log" # Файл лога
21SCRIPT_LOG_PREFIX='[%Y-%m-%d %H:%M:%S.%3N]' # Формат метки времени
22SCRIPT_LOCK="${SCRIPT_DIR}/${SCRIPT_NAME%.*}.lock" # Файл блокировки
23# Используется для логирования и предотвращения одновременного запускаСкрипт включает строгий режим безопасности (set -Eeuo pipefail), задаёт безопасный PATH, определяет базовые переменные - свой PID, путь и имя, а также файлы для лога и блокировки, чтобы можно было писать логи и предотвращать одновременный запуск.
Сниппет №2 - блокировка для предотвращения повторного запуска скрипта
1#!/usr/bin/env bash
2
3SCRIPT_PID=$$ # PID скрипта
4# Абсолютный путь к каталогу скрипта
5SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P)
6SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")" # Имя файла скрипта
7SCRIPT_LOCK="${SCRIPT_DIR}/${SCRIPT_NAME%.*}.lock" # Файл блокировки
8
9# Функция блокировки
10setup_lock() {
11 # Открываем файл блокировки и сохраняем дескриптор
12 exec {fd_lock}>> "${SCRIPT_LOCK}"
13
14 # Пытаемся захватить блокировку (без ожидания)
15 if ! flock -n "$fd_lock"; then
16 echo "Script instance is already running, exiting..."
17 exit 1 # Выходим, если файл уже заблокирован
18 fi
19
20 # Записываем PID текущего процесса в lock-файл
21 echo "$SCRIPT_PID" > "$SCRIPT_LOCK"
22}
23
24# Инициализация блокировки
25setup_lockЭтот код предотвращает одновременный запуск нескольких экземпляров одного и того же скрипта.
Подробнее
При запуске скрипта:
- Создаётся lock-файл рядом со скриптом (
.lock), ассоциированный с файловым дескрипторомfd_lock. flockпытается установить эксклюзивную блокировку.- если другой экземпляр уже запущен, блокировка занята - скрипт выводит сообщение и завершает работу
- если блокировка свободна, текущий процесс получает эксклюзивный доступ
- В lock-файл записывается PID, что упрощает диагностику (можно увидеть, какой процесс удерживает блокировку).
Такой механизм используется в системных и cron-скриптах, чтобы не запустить параллельно несколько копий одной задачи (например, резервного копирования или синхронизации).flock гарантирует атомарность - два процесса не смогут захватить один и тот же lock-файл одновременно.
Сниппет №3 - действия очистки при завершении скрипта
1#!/usr/bin/env bash
2
3SCRIPT_PID=$$ # PID скрипта
4# Абсолютный путь к каталогу скрипта
5SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd -P)
6SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")" # Имя файла скрипта
7SCRIPT_LOCK="${SCRIPT_DIR}/${SCRIPT_NAME%.*}.lock" # Файл блокировки
8
9# Открываем файл блокировки и сохраняем дескриптор
10exec {fd_lock}>> "${SCRIPT_LOCK}"
11# Пытаемся захватить блокировку (без ожидания)
12flock -n "$fd_lock"
13# Записываем PID текущего процесса в lock-файл
14echo "$SCRIPT_PID" > "$SCRIPT_LOCK"
15
16# Функция очистки, вызываемая при завершении работы скрипта (сработке trap)
17cleanup() {
18 # Сбрасываем все установленные trap'ы, чтобы избежать рекурсивных вызовов
19 trap - SIGINT SIGTERM SIGHUP SIGQUIT ERR EXIT
20
21 # Если файловый дескриптор был открыт - закрываем его
22 [[ -n "${fd_lock-}" ]] && exec {fd_lock}>&-
23
24 # Проверяем, существует ли lock-файл и содержит ли он PID текущего процесса
25 # Это предотвращает случайное удаление чужого lock-файла
26 if [[ -f "$SCRIPT_LOCK" && $(< "$SCRIPT_LOCK") -eq $SCRIPT_PID ]]; then
27 # Удаляем lock-файл, освобождая ресурс
28 rm -f "$SCRIPT_LOCK"
29 fi
30}
31
32# Устанавливаем trap (ловушку),
33# чтобы при выходе из скрипта, вызывалась функция cleanup
34# Старайтесь завершать trap'ы командой exit
35trap 'RC=$?; cleanup; exit $RC' SIGINT SIGHUP SIGTERM SIGQUIT ERR EXITЭтот сниппет демонстрирует использование trap для вызова функции cleanup, которая обеспечивает корректное завершение скрипта и очистку ресурсов (на примере удаления lock-файла).
Подробнее
В этом сниппете удаление lock-файла - лишь пример применения механизма trap, который демонстрирует, как можно:
- отлавливать сигналы (
SIGINT,SIGTERM,SIGHUP,SIGQUIT) и ошибки (ERR,EXIT); - выполнять единый блок завершения (функция
cleanup), независимо от причины выхода скрипта; - гарантировать корректную очистку и завершение любых операций (не только lock-файлов - сюда могут входить временные файлы, сетевые соединения, монтирования и т.д.).
Сниппет №4 - настройка логирования вывода скрипта
1#!/usr/bin/env bash
2
3# Базовые переменные
4SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd -P)
5SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
6SCRIPT_LOG="${SCRIPT_DIR}/${SCRIPT_NAME%.*}.log"
7SCRIPT_LOG_PREFIX='[%Y-%m-%d %H:%M:%S.%3N]' # Формат временной метки
8
9# Параметры логирования
10LOG_TO_STDOUT=1 # Лог в stdout
11LOG_TO_FILE=0 # Лог в файл
12LOG_TO_SYSLOG=0 # Лог в syslog
13
14# Функция обработки и перенаправления логов
15log_pipe() {
16 while IFS= read -r line; do
17 log_line="$(date +"${SCRIPT_LOG_PREFIX}") - $line" # Добавляем метку времени
18 (( LOG_TO_STDOUT )) && echo "$log_line" # Вывод в stdout
19 (( LOG_TO_FILE )) && echo "$log_line" >> "$SCRIPT_LOG" # В файл
20 (( LOG_TO_SYSLOG )) && logger -t "$SCRIPT_NAME" -- "$line" # В syslog
21 done
22}
23
24# Перенаправляем stdout/stderr через log_pipe
25exec > >(log_pipe) 2>&1
26
27# Тестовые выводы
28echo test123
29echo "Hello Friend"
30printf "|%s|%s|\n" "Hello" "Friend"
31
32echo "----------------------------------"Этот скрипт на Bash настраивает логирование, перенаправляя stdout и stderr в функцию log_pipe, которая добавляет временные метки и отправляет логи в stdout, файл и/или syslog, в зависимости от заданных параметров (по умолчанию вывод в stdout).
Подробнее про данный способ логирования смотрите эту заметку.
Сниппет №5 - цветное логирование вывода скрипта
1#!/usr/bin/env bash
2
3# Функция инициализации цвета
4setup_colors() {
5 if [[ -t 1 ]] && [[ -z ${NO_COLOR-} ]] && [[ "${TERM-}" != "dumb" ]]; then
6 RESET=$(tput sgr0)
7 RED=$(tput setaf 1) GREEN=$(tput setaf 2)
8 YELLOW=$(tput setaf 3) BLUE=$(tput setaf 4)
9 PURPLE=$(tput setaf 5) CYAN=$(tput setaf 6)
10 else
11 RESET="" RED="" GREEN="" YELLOW="" BLUE="" PURPLE="" CYAN=""
12 fi
13}
14
15log_info() { printf "${BLUE}[INFO] - %s\n${RESET}" "$*"; }
16log_warn() { printf "${YELLOW}[WARN]} - %s\n${RESET}" "$*"; }
17log_error() { printf "${RED}[ERROR] - %s\n${RESET}" "$*" >&2; exit 1; }
18
19# Инициализация цвета и пример вывода
20setup_colors
21
22log_info "Информационное сообщение"
23log_warn "Сообщение-предупреждение"
24log_error "Сообщение об ошибке + выход из скрипта"Этот сниппет проверяет, можно ли безопасно выводить цветной текст: он убеждается, что STDOUT подключён к настоящему терминалу, что переменная NO_COLOR не установлена (то есть цвет явно не запрещён), и что текущий терминал не является “dumb” и поддерживает управляющие последовательности. Если все условия соблюдены, скрипт включает вывод цветовых кодов; иначе - отключает цвета.
Подробнее

[[ -t 1 ]]- stdout - это терминал (скрипт запущен в интерактивном терминале, а не в пайпе/файле);[[ -z ${NO_COLOR-} ]]- переменнаяNO_COLORНЕ установлена - разрешено выводить цвета;[[ "${TERM-}" != "dumb" ]]- терминал не dumb (а значит, поддерживает управляющие последовательности).
Если предпочитаете управляющие последовательности, то вот:
RESET='\033[0m'
RED='\033[0;31m' GREEN='\033[0;32m'
YELLOW='\033[0;33m' BLUE='\033[0;34m'
PURPLE='\033[0;35m' CYAN='\033[0;36m'Почему tput, а не явное указание управляющих последовательностей?
tput setaf использует terminfo и подбирает правильные escape-последовательности для конкретного терминала.
Это важно, если скрипт может работать:
- на разных Linux-дистрибутивах
- внутри tmux/screen
- в контейнерах Docker
- в нестандартных терминалах (например, alacritty, kitty, vt100, xterm, macOS Terminal)
ANSI-коды (\033[0;31m) - это xterm-совместимый вариант. В 95% случаев сработает, но не гарантированно везде.
Сниппет №6 - проверка наличия утилиты в системе
1#!/usr/bin/env bash
2
3# Функция вывода сообщения об ошибке
4log_error() { printf "[ERROR] - %s\n" "$*" >&2; exit 1; }
5
6# Функция проверки
7check_utils() {
8 local utils=("$@")
9
10 for util in "${utils[@]}"; do
11 if ! command -v "$util" &> /dev/null; then
12 log_error "Utility $util is not installed"
13 fi
14 done
15}
16
17# Пример проверки утилит
18check_utils "ping" "mtr" "curl" "ssh"Функция check_utils принимает имя утилиты (одной или нескольких) в качестве аргумента и проверяет, установлена ли она в системе с помощью команды command -v. Если утилита не найдена, вызывается log_error для вывода сообщения об ошибке и завершения скрипта.
Подробнее про command -v
command -v встроенная команда оболочки, которая проверяет, является ли команда функцией Bash, встроенной командой Bash, алиасом или исполняемым файлом, расположенным в директориях из переменной окружения $PATH. В последнем случае выводит полный путь до исполняемого файла. Часто command -v используется в качестве альтернативы which, которая является внешней утилитой.
Сниппет №7 - обработка аргументов командной строки
1#!/usr/bin/env bash
2
3# Параметры безопасности
4set -Eeuo pipefail
5
6# Справка скрипта
7usage() {
8cat <<EOF
9Usage: ${BASH_SOURCE[0]} [OPTIONS] --backup DIR SRC_FILES
10
11Options:
12 -h, --help показать эту справку
13 -v, --verbose verbose режим (set -x)
14 -c, --check dry run режим
15 -b, --backup-dir DIR директория для backup
16 --backup-dir=DIR альтернативный синтаксис
17
18Examples:
19 ${BASH_SOURCE[0]} -b bkp_dir src_dir
20 ${BASH_SOURCE[0]} --check --backup /mnt/backup /opt/data/data.db
21EOF
22}
23
24parse_params() {
25 BACKUP_DIR=""
26 CHECK_MODE=0
27
28 # Ручной разбор аргументов (короткие и длинные ключи)
29 while [[ $# -gt 0 ]]; do
30 local key="$1"
31 case "$key" in
32 -h|--help) usage; exit 0 ;; # help
33 -v|--verbose) set -x ;; # verbose
34 -c|--check) CHECK_MODE=1 ;; # check mode
35 -b|--backup-dir) # backup dir
36 [[ -n "$2" ]] || { echo "Option "$1" needs arg" >&2; exit 1; }
37 BACKUP_DIR="$2"; shift ;;
38 --backup-dir=*) BACKUP_DIR="${1#*=}" ;; # --backup-dir=DIR
39 --) shift; break ;; # конец параметров
40 -*) usage; exit 1 ;; # неизвестный параметр
41 *) break ;; # позиционные аргументы
42 esac
43 shift
44 done
45
46 # Позиционные аргументы
47 SRC_FILES="$@"
48
49 # Проверка наличия обязательных параметров
50 [[ -n $BACKUP_DIR && -n $SRC_FILES ]] || { usage; exit 1; }
51}
52
53parse_params "$@"
54
55echo -e "Starting backup...\n"
56
57if (( CHECK_MODE )); then
58 echo "Dry run mode. Command to run:"
59 echo "tar --create --verbose --gzip --file=${BACKUP_DIR}/archive.tgz ${SRC_FILES[@]}"
60else
61 tar --create --verbose --gzip --file="${BACKUP_DIR}"/archive.tgz "${SRC_FILES[@]}"
62fiДанный сниппет демонстрирует пример (ПОДЧЁРКИВАЮ, лишь ПРИМЕР) ручной обработки и использования аргументов командной строки в Bash. Поддерживаются короткие и длинные ключи, проверка обязательных параметров, разделение опций и позиционных аргументов перед выполнением основной логики, на примере резервного копирования.
Подробнее
set -Eeuo pipefail - Включает безопасный режим выполнения: выход при ошибках, контроль unset-переменных и ошибок в pipeline;
usage() - Функция вывода справки: синтаксис запуска, список опций и примеры;
parse_params() - Основной парсер аргументов:
while [[ $# -gt 0 ]]- цикл по аргументам;case- обработка коротких и длинных ключей;-h/--help- показать help;-v/--verbose- включить трассировку (set -x);-c/--check- dry-run режим;-b/--backup-dir- директория backup;--- конец опций;shift- переход к следующему аргументу.
SRC_FILES="$@" - все оставшиеся аргументы считаются позиционными (список файлов для бэкапа).
После парсинга проверяется наличие обязательных переменных: директория бэкапа и хотя бы один исходный файл/директория.
И в конце основная логика:
- check mode - просто вывод команды (
tar); - обычный режим - выполнение команды.
Сниппет №8 - проверка занятого пространства на разделе
1log_info() { printf "[INFO] - %s\n" "$*"; }
2log_error() { printf "[ERROR] - %s\n" "$*" >&2; exit 1; }
3
4check_disk_space() {
5 local output_dir="${1-}"
6 log_info "Checking available disk space..."
7
8 local disk_usage_percent
9 disk_usage_percent=$(df "$output_dir" --output=pcent | tail -n 1 | tr -d ' %')
10
11 if (( disk_usage_percent > 95 )); then
12 log_error "More than 95% of disk space is used: ${disk_usage_percent}%. Terminating..."
13 else
14 log_info "Disk usage: ${disk_usage_percent}%"
15 fi
16}
17
18check_disk_space "/opt"
19
20check_disk_space "/var/lib"Функция check_disk_space принимает путь к директории, определяет процент использования диска с помощью команды df. Если использование диска превышает 95%, скрипт выводит сообщение об ошибке и аварийно завершает работу; в противном случае он выводит информационное сообщения о текущем % занятого пространства.


