Архив рассылок сообщества снова открыт. Читать письма 2003-2009
Главная/Блог/Терминал
Терминал9 мин чтения

Bash-скрипты для автоматизации рутины: пишем с нуля

Практическое руководство по Bash-скриптам: от структуры и защитных флагов до бэкапа папки и запуска через cron.

Любую рутину, которую вы повторяете в терминале руками, можно превратить в скрипт и забыть о ней. Bash-скрипты - это простой способ автоматизировать бэкапы, чистку логов, обработку файлов и запускать всё это по расписанию. В этой статье соберём практическую базу: от структуры скрипта до реальных примеров, которые можно поставить на cron уже сегодня.

Структура надёжного скрипта

Любой скрипт начинается с шебанга - строки, которая говорит системе, чем его выполнять. Рекомендую использовать вариант через env: он находит bash в PATH и работает на большинстве систем.

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

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

Не забудьте сделать файл исполняемым.

chmod +x myscript.sh
./myscript.sh

Переменные и аргументы

Переменные в Bash объявляются без пробелов вокруг знака равно. Обращение к значению - через $, и хорошая привычка всегда брать значения в двойные кавычки, чтобы пробелы в путях не ломали логику.

name="backup"
target_dir="/var/www"
date_stamp="$(date +%Y-%m-%d)"

echo "Запускаю $name для $target_dir на $date_stamp"

Аргументы, переданные скрипту, доступны как $1, $2 и так далее; $# хранит их количество, а $@ - все сразу. Полезно проверять, что аргумент вообще передали.

if [ "$#" -lt 1 ]; then
  echo "Использование: $0 <путь>" >&2
  exit 1
fi

source_path="$1"

Условия и циклы

Условия проверяют состояние: существует ли файл, равны ли значения, пуста ли строка. Циклы позволяют пройтись по списку файлов или строк.

# проверка существования каталога
if [ -d "$source_path" ]; then
  echo "Каталог найден"
else
  echo "Каталог не найден" >&2
  exit 1
fi

# перебор всех .log файлов
for file in /var/log/myapp/*.log; do
  echo "Обрабатываю $file"
done

Оператор [ -d ] проверяет каталог, [ -f ] - обычный файл, [ -z ] - пустую строку. Перенаправление >&2 отправляет сообщение в поток ошибок, что правильно для диагностики.

Функции для повторяющейся логики

Когда один и тот же кусок кода встречается несколько раз, вынесите его в функцию. Это делает скрипт читаемым и упрощает поддержку. Удобно завести функцию логирования с меткой времени.

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

die() {
  echo "ОШИБКА: $*" >&2
  exit 1
}

log "Скрипт стартовал"

Пример 1: бэкап папки

Соберём полноценный скрипт, который упаковывает каталог в архив с датой в имени и складывает его в папку бэкапов. Он проверяет вход, создаёт целевую папку и логирует результат.

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

src="${1:?Укажите папку для бэкапа}"
backup_dir="/backups"
stamp="$(date +%Y-%m-%d_%H%M%S)"
archive="$backup_dir/$(basename "$src")_$stamp.tar.gz"

log() { echo "[$(date '+%F %T')] $*"; }

[ -d "$src" ] || { echo "Нет папки: $src" >&2; exit 1; }
mkdir -p "$backup_dir"

log "Архивирую $src"
tar -czf "$archive" -C "$(dirname "$src")" "$(basename "$src")"
log "Готово: $archive"

Конструкция ${1:?сообщение} завершит скрипт с внятной ошибкой, если аргумент не передан - удобная защита в одну строку.

Пример 2: чистка старых логов

Второй частый сценарий - удаление логов старше N дней, чтобы диск не забивался. Здесь помогает утилита find.

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

log_dir="/var/log/myapp"
days=14

# найти и удалить .log старше 14 дней
find "$log_dir" -type f -name "*.log" -mtime +"$days" -print -delete

Флаг -mtime +14 отбирает файлы, изменённые более 14 дней назад, -print покажет их имена, а -delete удалит. Перед первым запуском уберите -delete, чтобы просто посмотреть список кандидатов - так безопаснее.

Запуск по расписанию через cron

Чтобы скрипт работал сам, добавьте его в crontab - планировщик задач. Откройте редактор расписания командой crontab -e и добавьте строку. Формат: минута, час, день месяца, месяц, день недели, затем команда.

# бэкап /var/www каждый день в 3:30 ночи
30 3 * * * /home/user/backup.sh /var/www >> /var/log/backup.log 2>&1

# чистка логов по понедельникам в 4:00
0 4 * * 1 /home/user/clean-logs.sh

Конструкция >> файл 2>&1 сохраняет весь вывод и ошибки в лог - это очень важно, ведь при запуске из cron вы не видите терминал. Указывайте в crontab полные пути и к скрипту, и к файлам внутри него: у cron минимальное окружение, и относительные пути часто не работают.

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

С этой базой вы уже можете автоматизировать большую часть повседневной рутины. Начните с малого - оберните в скрипт одну надоевшую команду, добавьте защитные флаги и логирование, а затем поставьте на расписание.

Вернуться в блог