$ 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 мин·84
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 – для начинающих!

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

Перейти к курсу
Solidity DLC - поймай, если сможешь

Solidity DLC - поймай, если сможешь

Аудит смарт-контрактов на реальных взломах. The DAO, Parity, Wormhole, Ronin, Euler и ещё 7 разборов: что пошло не так, сколько потеряли и что бы спасло. Атаки и защиты на Foundry, план входа в профессию аудитора.

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

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

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

Перейти к курсу
Solidity pro - всё или ничего

Solidity pro - всё или ничего

Как пишут контракты, которые работают в основной сети. Наследование и OpenZeppelin, паттерны продакшена, оптимизация газа, ABI, delegatecall и подписи. 7 модулей, 33 урока, а в финале собственное dApp: мини-DAO с токеном, голосованием и казной.

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

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

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

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

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

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

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

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

29 июля 2026 г.
820
Как выучить программирование самому и бесплатно: с чего начать и в каком порядке
выучить

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

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

21 сентября 2026 г.
1950
Что такое HTML и чем он отличается от CSS — объясню простыми словами и на примерах
такое

Что такое HTML и чем он отличается от CSS — объясню простыми словами и на примерах

Разберём, из чего состоит веб-страница: что делает HTML (смысл и структура) и что делает CSS (оформление). В конце соберёте мини-страницу и поймёте, что нужно учить в каком порядке.

30 октября 2026 г.
100
Cargo для продакшена: workspaces, фичи и стратегия версий зависимостей
cargo

Cargo для продакшена: workspaces, фичи и стратегия версий зависимостей

Разберём, как организовать Rust workspace, управлять optional features, фиксировать версии библиотек и уменьшать “дрейф” зависимостей при командной разработке и CI.

18 сентября 2026 г.
1940
Что такое SQL и зачем он нужен новичку: как думать о данных простыми словами
такое

Что такое SQL и зачем он нужен новичку: как думать о данных простыми словами

Разберём, что такое базы данных и SQL без сложной теории: как выбирать данные, фильтровать их и собирать таблицы в отчёт. В конце — короткий план, как потренироваться и собрать первые запросы для портфолио.

28 октября 2026 г.
220

Комментарии

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

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

Содержание

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