$ sudo teach|
    $ sudo teach|
    IT school
  • Telegram
  • Партнёрам
  • Все курсы
$ sudo teach IT
OOO "SALEPROFIT"Контакты и реквизитыIT-Park Logo

Школа

  • Блог
  • Проверить сертификат

Сотрудничество

  • Стать учителем
  • Партнёрская программа
  • О проекте

Право

  • Оферта
  • Политика конфиденциальности

© 2023–2026 $ sudo teach IT™. All Rights Reserved. Public user contributions licensed under CC BY-SA 4.0 license with attribution required
TelegramGitHubYouTube
ГлавнаяБлогBash-скрипты вместо рутины: 7 сценариев, которые экономят время каждый день

Bash-скрипты вместо рутины: 7 сценариев, которые экономят время каждый день

$ sudo teach IT
·16 июля 2026 г.·9 мин·70
Bash-скрипты вместо рутины: 7 сценариев, которые экономят время каждый день

Практические скрипты для автоматизации бэкапов, мониторинга процессов, массового переименования файлов и деплоя — с разбором каждой строки.

Содержание
Прежде чем начать: несколько базовых принциповСценарий 1: Автоматический бэкап с ротациейСценарий 2: Мониторинг процесса и автоперезапускСценарий 3: Массовое переименование файловСценарий 4: Проверка доступности сайтовСценарий 5: Деплой приложения с откатомСценарий 6: Анализ логов и генерация отчётаСценарий 7: Очистка дискового пространстваТипичные ошибки, которые ломают скриптыВывод

Каждый системный администратор или разработчик рано или поздно замечает: значительная часть рабочего дня уходит на одни и те же действия. Проверить, не упал ли процесс. Сделать бэкап перед деплоем. Переименовать двести файлов по новому шаблону. Отправить отчёт на почту. Всё это — задачи, которые человек выполняет хуже машины: медленнее, с ошибками и с раздражением.

Bash существует с 1989 года и по сей день остаётся главным инструментом автоматизации в Unix-мире. Не потому что он красив или современен, а потому что он есть везде: на любом Linux-сервере, в macOS, в WSL под Windows. Скрипт, написанный сегодня, будет работать на продакшн-сервере через десять лет без единого изменения.

В этой статье — семь конкретных сценариев с разбором кода. Не абстрактные примеры из учебника, а задачи, которые возникают в реальной работе.


Прежде чем начать: несколько базовых принципов

Хороший bash-скрипт — это не просто набор команд, склеенных в файл. Есть несколько практик, которые отделяют рабочий инструмент от хрупкой поделки.

Shebang и строгий режим. Каждый скрипт должен начинаться с:

code
#!/usr/bin/env bash
set -euo pipefail

set -e останавливает выполнение при любой ошибке. set -u запрещает использование необъявленных переменных. set -o pipefail гарантирует, что ошибка в середине пайпа не будет проглочена. Без этих трёх строк скрипт может продолжать работу после сбоя и натворить дел.

Логирование. Скрипт, который молчит, — это чёрный ящик. Даже простая функция вывода с временной меткой делает отладку в разы проще:

code
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}

Проверка зависимостей. Если скрипт требует rsync, jq или curl, стоит проверить их наличие в начале, а не падать с непонятной ошибкой посередине работы.

code
for cmd in rsync curl jq; do
    command -v "$cmd" &>/dev/null || { echo "Не найдена команда: $cmd"; exit 1; }
done

Сценарий 1: Автоматический бэкап с ротацией

Самая классическая задача. Нужно каждую ночь архивировать директорию, хранить последние семь копий и удалять старые.

code
#!/usr/bin/env bash
set -euo pipefail

BACKUP_SRC="/var/www/myapp"
BACKUP_DST="/mnt/backups/myapp"
KEEP_DAYS=7
TIMESTAMP=$(date '+%Y%m%d_%H%M%S')
ARCHIVE_NAME="backup_${TIMESTAMP}.tar.gz"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

mkdir -p "$BACKUP_DST"

log "Создаём архив: $ARCHIVE_NAME"
tar -czf "${BACKUP_DST}/${ARCHIVE_NAME}" -C "$(dirname "$BACKUP_SRC")" "$(basename "$BACKUP_SRC")"

log "Удаляем бэкапы старше $KEEP_DAYS дней"
find "$BACKUP_DST" -name "backup_*.tar.gz" -mtime +"$KEEP_DAYS" -delete

log "Готово. Текущие бэкапы:"
ls -lh "$BACKUP_DST"

Что здесь важно: tar -C меняет рабочую директорию перед архивацией, поэтому внутри архива не будет абсолютных путей вроде /var/www/myapp/... — только myapp/.... Это упрощает восстановление. find -mtime +7 находит файлы, изменённые более семи дней назад, и удаляет их. Скрипт добавляется в cron одной строкой: 0 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1.


Сценарий 2: Мониторинг процесса и автоперезапуск

Процесс упал — нужно его поднять и записать событие в лог. Простой watchdog без лишних зависимостей.

code
#!/usr/bin/env bash
set -euo pipefail

PROCESS_NAME="myapp"
START_CMD="/opt/myapp/bin/start.sh"
LOG_FILE="/var/log/watchdog.log"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }

if pgrep -x "$PROCESS_NAME" > /dev/null; then
    log "Процесс $PROCESS_NAME работает нормально"
else
    log "ВНИМАНИЕ: процесс $PROCESS_NAME не найден. Перезапускаем..."
    $START_CMD
    sleep 3
    if pgrep -x "$PROCESS_NAME" > /dev/null; then
        log "Процесс успешно перезапущен"
    else
        log "ОШИБКА: не удалось запустить $PROCESS_NAME"
        # Здесь можно добавить отправку алерта
        exit 1
    fi
fi

pgrep -x ищет процесс по точному имени (флаг -x исключает частичные совпадения). tee -a одновременно выводит сообщение в терминал и дописывает его в лог-файл. Скрипт запускается через cron каждые пять минут: */5 * * * * /opt/scripts/watchdog.sh.


Сценарий 3: Массовое переименование файлов

Фотограф сдал 300 файлов с именами вроде IMG_4521.jpg. Нужно переименовать их в photo_001.jpg, photo_002.jpg и так далее.

code
#!/usr/bin/env bash
set -euo pipefail

SOURCE_DIR="${1:-.}"  # Директория как аргумент, по умолчанию текущая
PREFIX="${2:-photo}"
EXTENSION="${3:-jpg}"
COUNTER=1

for file in "$SOURCE_DIR"/*."$EXTENSION"; do
    # Пропускаем, если файлов с таким расширением нет
    [[ -e "$file" ]] || continue

    NEW_NAME="${SOURCE_DIR}/${PREFIX}_$(printf '%03d' "$COUNTER").${EXTENSION}"
    echo "Переименовываем: $(basename "$file") -> $(basename "$NEW_NAME")"
    mv "$file" "$NEW_NAME"
    ((COUNTER++))
done

echo "Готово. Переименовано файлов: $((COUNTER - 1))"

Несколько нюансов. ${1:-.} — это подстановка с умолчанием: если первый аргумент не передан, используется . (текущая директория). printf '%03d' форматирует число с ведущими нулями: 001, 002, 099. Конструкция [[ -e "$file" ]] || continue защищает от ситуации, когда glob не находит файлов и передаёт в цикл буквальную строку *.jpg.

Перед запуском на реальных данных разумно добавить флаг --dry-run: заменить mv на echo mv и проверить, что скрипт делает именно то, что ожидается.


Сценарий 4: Проверка доступности сайтов

Нужно раз в минуту проверять список URL и отправлять уведомление в Telegram, если что-то недоступно.

code
#!/usr/bin/env bash
set -euo pipefail

SITES=(
    "https://example.com"
    "https://api.example.com/health"
    "https://staging.example.com"
)

TG_BOT_TOKEN="ваш_токен"
TG_CHAT_ID="ваш_chat_id"

send_alert() {
    local message="$1"
    curl -s -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
        -d "chat_id=${TG_CHAT_ID}" \
        -d "text=${message}" > /dev/null
}

for url in "${SITES[@]}"; do
    HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url")

    if [[ "$HTTP_CODE" -ne 200 ]]; then
        MESSAGE="⚠️ Сайт недоступен: $url (код: $HTTP_CODE) — $(date '+%H:%M:%S')"
        echo "$MESSAGE"
        send_alert "$MESSAGE"
    else
        echo "OK [$HTTP_CODE]: $url"
    fi
done

curl -s -o /dev/null -w "%{http_code}" — классический приём: подавляем вывод тела ответа (-o /dev/null), но получаем HTTP-статус через формат вывода (-w). --max-time 10 гарантирует, что зависший сервер не заблокирует скрипт на неопределённое время. Массив SITES с отдельным перебором через "${SITES[@]}" — правильный способ работы с массивами в bash, который корректно обрабатывает пробелы в элементах.


Сценарий 5: Деплой приложения с откатом

Деплой без возможности отката — это хождение по канату без страховки. Вот минималистичный скрипт, который делает снапшот текущей версии перед обновлением.

code
#!/usr/bin/env bash
set -euo pipefail

APP_DIR="/opt/myapp"
BACKUP_DIR="/opt/myapp_backups"
REPO_URL="git@github.com:company/myapp.git"
BRANCH="${1:-main}"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

# Создаём снапшот текущей версии
SNAPSHOT="${BACKUP_DIR}/snapshot_$(date '+%Y%m%d_%H%M%S')"
log "Создаём снапшот: $SNAPSHOT"
cp -r "$APP_DIR" "$SNAPSHOT"

# Функция отката — вызывается при ошибке
rollback() {
    log "ОШИБКА при деплое. Откатываемся к предыдущей версии..."
    rm -rf "$APP_DIR"
    cp -r "$SNAPSHOT" "$APP_DIR"
    log "Откат выполнен"
    exit 1
}
trap rollback ERR

# Деплой
log "Получаем обновления из ветки $BRANCH"
cd "$APP_DIR"
git fetch origin
git checkout "$BRANCH"
git pull origin "$BRANCH"

log "Устанавливаем зависимости"
npm ci --production

log "Перезапускаем сервис"
systemctl restart myapp

log "Деплой завершён успешно"

Ключевой момент — trap rollback ERR. Это ловушка: при любой ошибке (ненулевой код возврата) bash автоматически вызовет функцию rollback. Это работает в связке с set -e. Такой подход гораздо надёжнее, чем ручная проверка if/else после каждой команды.

Тем, кто хочет разобраться с подобными конструкциями системно — от базового синтаксиса до написания полноценных инструментов автоматизации, — может пригодиться курс «Изучаем bash»: там эти механизмы разбираются последовательно, с практическими заданиями.


Сценарий 6: Анализ логов и генерация отчёта

Нужно каждое утро получать сводку по вчерашним ошибкам из nginx-лога: сколько было 4xx и 5xx, какие URL встречались чаще всего.

code
#!/usr/bin/env bash
set -euo pipefail

LOG_FILE="/var/log/nginx/access.log"
YESTERDAY=$(date -d "yesterday" '+%d/%b/%Y')
REPORT_FILE="/tmp/nginx_report_$(date '+%Y%m%d').txt"

{
    echo "=== Отчёт по логам nginx за $YESTERDAY ==="
    echo ""

    echo "--- Коды ответов ---"
    grep "$YESTERDAY" "$LOG_FILE" | \
        awk '{print $9}' | \
        sort | uniq -c | sort -rn

    echo ""
    echo "--- Топ-10 URL с ошибками 4xx ---"
    grep "$YESTERDAY" "$LOG_FILE" | \
        awk '$9 ~ /^4/ {print $7}' | \
        sort | uniq -c | sort -rn | head -10

    echo ""
    echo "--- Топ-10 URL с ошибками 5xx ---"
    grep "$YESTERDAY" "$LOG_FILE" | \
        awk '$9 ~ /^5/ {print $7}' | \
        sort | uniq -c | sort -rn | head -10

    echo ""
    echo "--- Топ-10 IP по количеству запросов ---"
    grep "$YESTERDAY" "$LOG_FILE" | \
        awk '{print $1}' | \
        sort | uniq -c | sort -rn | head -10

} > "$REPORT_FILE"

cat "$REPORT_FILE"
# mail -s "Nginx отчёт за $YESTERDAY" ops@company.com < "$REPORT_FILE"

Здесь вся работа построена на классической связке grep | awk | sort | uniq -c | sort -rn. awk '{print $9}' извлекает девятое поле — HTTP-статус в стандартном формате nginx. $9 ~ /^4/ — это регулярное выражение внутри awk: поле начинается с цифры 4. Фигурные скобки вокруг всего блока с перенаправлением > "$REPORT_FILE" — удобный способ записать вывод нескольких команд в один файл без повторения редиректа.


Сценарий 7: Очистка дискового пространства

Диск заполнился — нужно быстро найти виновников и убрать мусор.

code
#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log"
TMP_DIR="/tmp"
MAX_LOG_AGE=30  # дней
MIN_FREE_PERCENT=20

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

# Проверяем текущее состояние диска
check_disk() {
    local partition="${1:-/}"
    local used_percent
    used_percent=$(df "$partition" | awk 'NR==2 {gsub(/%/, "", $5); print $5}')
    echo "$used_percent"
}

USED=$(check_disk "/")
FREE=$((100 - USED))
log "Использовано: ${USED}%, свободно: ${FREE}%"

if [[ "$FREE" -gt "$MIN_FREE_PERCENT" ]]; then
    log "Места достаточно, очистка не требуется"
    exit 0
fi

log "Свободного места меньше ${MIN_FREE_PERCENT}%. Начинаем очистку..."

# Удаляем старые логи
log "Удаляем логи старше $MAX_LOG_AGE дней в $LOG_DIR"
find "$LOG_DIR" -name "*.log.*" -mtime +"$MAX_LOG_AGE" -delete
find "$LOG_DIR" -name "*.gz" -mtime +"$MAX_LOG_AGE" -delete

# Очищаем /tmp
log "Очищаем файлы в $TMP_DIR старше 7 дней"
find "$TMP_DIR" -mtime +7 -delete 2>/dev/null || true

# Очищаем кэш пакетного менеджера
if command -v apt-get &>/dev/null; then
    log "Очищаем кэш apt"
    apt-get clean -y
fi

USED_AFTER=$(check_disk "/")
log "После очистки использовано: ${USED_AFTER}% (было: ${USED}%)"

Обратите внимание на || true после второго find. Команда может завершиться с ошибкой, если у неё нет прав на удаление некоторых файлов в /tmp — это нормально. || true предотвращает срабатывание set -e в этом конкретном месте. Функция check_disk использует awk с gsub для удаления символа % из вывода df перед арифметическим сравнением — без этого bash не сможет сравнить строку "45%" с числом.


Типичные ошибки, которые ломают скрипты

Пробелы в именах файлов. Конструкция for file in $FILES без кавычек сломается на первом же файле с пробелом в имени. Всегда используйте "$variable" и "${array[@]}".

Игнорирование кодов возврата. Без set -e скрипт продолжит работу после неудачной команды. Это особенно опасно в деплой-скриптах.

Хардкод паролей и токенов. Секреты должны храниться в переменных окружения или в файлах с ограниченными правами, но никак не в теле скрипта.

Отсутствие блокировки при параллельном запуске. Если cron запускает скрипт каждую минуту, а он выполняется две минуты, возникнут два параллельных экземпляра. Решается через flock:

code
exec 9>/var/lock/myscript.lock
flock -n 9 || { echo "Скрипт уже запущен"; exit 1; }

Неочищаемые временные файлы. Используйте trap для гарантированной очистки:

code
TMPFILE=$(mktemp)
trap 'rm -f "$TMPFILE"' EXIT

Вывод

Bash не требует изучения новых языков, установки интерпретаторов или настройки окружения. Это инструмент, который уже есть там, где нужно работать. Семь сценариев из этой статьи покрывают большую часть ежедневной рутины: резервное копирование, мониторинг, переименование, деплой, анализ логов, очистка диска.

Главное — писать скрипты с умом: строгий режим с самого начала, логирование, защита от типичных ошибок. Скрипт, написанный однажды правильно, работает годами без вмешательства.

Если хочется выстроить понимание bash системно — от синтаксиса и работы с переменными до написания полноценных инструментов, — курс «Изучаем bash» даёт именно такую последовательную базу с практикой на реальных задачах.

Войдите, чтобы поставить лайк и оставить комментарий.

Автор

$ sudo teach IT

Курс по теме

Изучаем bash

Разработка скриптов на bash

Бесплатно
Открыть курс

Продолжите обучение

Все курсы
Python – для начинающих!

Python – для начинающих!

С нуля до профессионального уровня. Подходит для всех. Учитесь каждый день и овладейте самым популярным языком программирования.

Перейти к курсу
Приложения для iPhone и Apple Watch на SwiftUI

Приложения для iPhone и Apple Watch на SwiftUI

Разработка приложений для iPhone и Apple Watch на SwiftUI: навигация, SwiftData, виджеты, часы, выпуск. Нужен Mac с Xcode 27, сами устройства не нужны.

Перейти к курсу
Ботостроение Telegram

Ботостроение Telegram

Лёгкий, быстрый и доступный способ познакомиться с миром ботостроения в Telegram. Видео, конспекты, практика и помощь – всё у нас на курсе.

Перейти к курсу
Приложения для macOS на SwiftUI

Приложения для macOS на SwiftUI

Разработка приложений для Mac на SwiftUI: окна и меню, Liquid Glass, SwiftData, сеть, выпуск. Нужен Mac с macOS 27 и Xcode 27.

Перейти к курсу

Другие статьи

Пишем корректные bash-скрипты: обработка ошибок, строгие режимы и безопасные переменные
пишем

Пишем корректные bash-скрипты: обработка ошибок, строгие режимы и безопасные переменные

Покажем best practices: set -euo pipefail, ловля ошибок, корректное quoting и проверка входных параметров. Разберём мини-проект с устойчивым поведением.

24 июля 2026 г.
720
Изучаем bash “по месту”: работа с аргументами, безопасными переменными и функциями
изучаем

Изучаем bash “по месту”: работа с аргументами, безопасными переменными и функциями

Разберём практики, которые чаще всего ломают bash-скрипты: парсинг аргументов, quoting, set -euo pipefail, функции и обработка ошибок. В конце — шаблон-скелет скрипта для повторного использования.

29 июля 2026 г.
610
Создание Telegram бота в 2026 легко и просто! Полный курсы!
создание

Создание Telegram бота в 2026 легко и просто! Полный курсы!

19 июня 2026 г.
1421
Как выбрать, куда идти в IT: веб, боты, данные — без хаоса
выбрать

Как выбрать, куда идти в IT: веб, боты, данные — без хаоса

Разберём самые понятные направления для новичка (веб, боты, аналитика/данные) и чем они отличаются по шагам обучения. В конце вы получите простой план, как проверить, что вам подходит, и какой стартовый путь выбрать.

5 октября 2026 г.
580
Путь от README до демо: как собрать портфолио разработчика, чтобы его хотели смотреть
путь

Путь от README до демо: как собрать портфолио разработчика, чтобы его хотели смотреть

Разберём структуру репозитория, как упаковать проект в понятную историю (проблема → решение → запуск → метрики качества) и какие артефакты повышают доверие: скринкасты, архитектурная схема, чек-лист продакшн-готовности.

17 сентября 2026 г.
1070
Как понять, какой язык программирования учить первым: простой тест и выбор
понять

Как понять, какой язык программирования учить первым: простой тест и выбор

Помогу новичку выбрать первый язык без стресса: объясню варианты по целям (веб, боты, анализ данных), что учить в первую очередь и как не потратить месяцы впустую. В конце — краткий план старта на ближайшие недели.

2 октября 2026 г.
630

Комментарии

Станьте первым в обсуждении

Поделитесь мнением о статье или задайте вопрос автору

Содержание

Прежде чем начать: несколько базовых принциповСценарий 1: Автоматический бэкап с ротациейСценарий 2: Мониторинг процесса и автоперезапускСценарий 3: Массовое переименование файловСценарий 4: Проверка доступности сайтовСценарий 5: Деплой приложения с откатомСценарий 6: Анализ логов и генерация отчётаСценарий 7: Очистка дискового пространстваТипичные ошибки, которые ломают скриптыВывод