Собственно, сам список сниппетов:
Сниппет №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
3setup_colors() {
4 if [[ -t 1 ]] && [[ -z ${NO_COLOR-} ]] && [[ "${TERM-}" != "dumb" ]]; then
5 RESET=$(tput sgr0)
6 RED=$(tput setaf 1) GREEN=$(tput setaf 2)
7 YELLOW=$(tput setaf 3) BLUE=$(tput setaf 4)
8 PURPLE=$(tput setaf 5) CYAN=$(tput setaf 6)
9 else
10 RESET="" RED="" GREEN="" YELLOW="" BLUE="" PURPLE="" CYAN=""
11 fi
12}
13
14log_info() { printf "${BLUE}[INFO] - %s\n${RESET}" "$*"; }
15log_warn() { printf "${YELLOW}[WARN]} - %s\n${RESET}" "$*"; }
16log_error() { printf "${RED}[ERROR] - %s\n${RESET}" "$*" >&2; exit 1; }
17
18# Инициализация цвета и пример вывода
19setup_colors
20
21log_info "Информационное сообщение"
22log_warn "Сообщение-предупреждение"
23log_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
3log_error() { printf "[ERROR] - %s\n" "$*" >&2; exit 1; }
4
5check_utils() {
6 local utils=("$@")
7
8 for util in "${utils[@]}"; do
9 if ! command -v "$util" &> /dev/null; then
10 log_error "Utility $util is not installed"
11 fi
12 done
13}
14
15check_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
usage() {
cat <<EOF
Usage: ${BASH_SOURCE[0]} [-h] [-v] -a|-s [-b DIR] SRC DST
-h help
-v verbose mode
-a apply
-s save
-b DIR backup dir
EOF
}
parse_params() {
while getopts ":vhasb:h" opt; do
case "$opt" in
h) usage; exit 0 ;;
v) set -x ;;
a) APPLY=1 ;;
s) SAVE=1 ;;
b) BACKUP="$OPTARG" ;;
:) echo "Option -$OPTARG needs arg" >&2; exit 1 ;;
*) usage; exit 1 ;;
esac
done
shift $((OPTIND-1))
SRC="$1" DST="$2"
(( APPLY || SAVE )) || { echo "Use -a or -s" >&2; exit 1; }
[[ $SRC && $DST ]] || { usage; exit 1; }
}
parse_params "$@"
echo "apply=$APPLY save=$SAVE backup=$BACKUP"
echo "src=$SRC dst=$DST"Данный сниппет обрабатывает аргументы командной строки с помощью встроенной в оболочку команды getopts, позволяя включить справку (-h), режим отладки (-v через set -x), выбрать один из режимов работы (-a - apply или -s - save) и передать параметр для опции -b. После разбора опций он сдвигает аргументы (shift), извлекает позиционные SRC и DST, проверяет корректность вызова (наличие одного из режимов и обязательных аргументов) и в конце выводит разобранные значения, служащие основой для дальнейшей логики скрипта.
Подробнее
usage()- печатает справку и ожидаемый синтаксис запуска;getopts ":vhasb:h":в начале –> тихий режим ошибок;v h a s b–> допустимые опции;b:–>-bтребует аргумент ($OPTARG);
case "$opt"-h–> показать help и выйти;-v–>set -x(включить трассировку);-a–> режим apply;-s–> режим save;-b DIR–> путь бэкапа;:–> у опции нет аргумента;*–> неизвестная опция;
shift $((OPTIND-1))- убирает разобранные опции –> остаются позиционные аргументы;SRC DST- первый и второй позиционные аргументы;- Валидация
- нужен
-aили-s; - нужны
SRCиDST;
- нужен
- Вывод - печать итоговых параметров (заглушка под логику).
Сниппет №8 - проверка занятого пространства на разделе
log_info() { printf "[INFO] - %s\n" "$*"; }
log_error() { printf "[ERROR] - %s\n" "$*" >&2; exit 1; }
check_disk_space() {
local output_dir="${1-}"
log_info "Checking available disk space..."
local disk_usage_percent
disk_usage_percent=$(df "$output_dir" --output=pcent | tail -n 1 | tr -d ' %')
if (( disk_usage_percent > 95 )); then
log_error "More than 95% of disk space is used: ${disk_usage_percent}%. Terminating..."
else
log_info "Disk usage: ${disk_usage_percent}%"
fi
}
check_disk_space "/opt"
check_disk_space "/var/lib"Функция check_disk_space принимает путь к директории, определяет процент использования диска с помощью команды df. Если использование диска превышает 95%, скрипт выводит сообщение об ошибке и аварийно завершает работу; в противном случае он выводит информационное сообщения о текущем % занятого пространства.


