Скрипт либо экономит нервы, либо создаёт тихие 3 часа ночи «почему бэкап пустой». Ниже — правила, из‑за которых автоматизация переживает обновление ноутбука и переезд на новый VPS ⚙️
Когда скрипт, а когда нет #
| Задача | Инструмент |
|---|---|
| Раз в день rsync каталога | bash + cron/timer |
| Реакция на webhook / очередь | нормальный сервис (systemd, docker) |
| Деплой с тестами | CI (Forgejo Actions), не cron «git pull» |
| Секреты | rbw/Infisical, не TOKEN=... в скрипте |
Шаблон безопасного bash #
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
readonly LOG_DIR="${LOG_DIR:-$HOME/var/log}"
readonly SRC="${SRC:-$HOME/data}"
readonly DST="${DST:-/Volumes/Backup/data}"
mkdir -p "$LOG_DIR"
log() { printf '%s %s\n' "$(date -Iseconds)" "$*" | tee -a "$LOG_DIR/backup.log"; }
need() { command -v "$1" >/dev/null || { log "missing: $1"; exit 127; }; }
need rsync
if [[ ! -d "$SRC" ]]; then
log "SRC not found: $SRC"
exit 1
fi
log "start $SRC -> $DST"
rsync -aH --delete --stats "$SRC/" "$DST/"
log "done"Почему так:
set -euo pipefail— падаем на ошибках, не глотаем пустые переменные;- пути через env — удобно гонять тот же скрипт на другой машине;
- лог с timestamp — иначе через месяц не вспомните, что случилось.
Идемпотентность #
Повторный запуск не должен удваивать ущерб:
# плохо: каждый раз append без границы
cat report.txt >> archive.txt
# лучше: целевое состояние
install -m 644 report.txt "$DST/report.txt"
# или rsync, который сам сводит деревоРасписание #
Linux: systemd timer (предпочтительнее cron) #
# ~/.config/systemd/user/backup.service
[Service]
Type=oneshot
ExecStart=%h/bin/backup.sh# ~/.config/systemd/user/backup.timer
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.targetsystemctl --user daemon-reload
systemctl --user enable --now backup.timermacOS: launchd #
<!-- ~/Library/LaunchAgents/ru.evgn.backup.plist -->
<!-- ProgramArguments: /Users/you/bin/backup.sh -->
<!-- StartCalendarInterval: Hour 3 -->launchctl load ~/Library/LaunchAgents/ru.evgn.backup.plistcron — когда «и так сойдёт» #
15 3 * * * /home/evgeny/bin/backup.sh >>/home/evgeny/var/log/backup.cron 2>&1Всегда абсолютные пути и явный user; cron не знает ваш интерактивный PATH.
Уведомления о провале #
Тишина — враг. Минимум:
if ! rsync …; then
curl -sS -d "backup failed on $(hostname)" ntfy.sh/your-topic || true
exit 1
fiИли MAILTO в cron, или systemd OnFailure=.
Чеклист перед «поставил и забыл» #
- Сухой прогон вручную под тем же user, что и scheduler.
- Логи ротируются (
logrotate/newsyslog). - Секреты не в argv (
ps auxих видит) — только env/файл 600. - Есть алерт на отсутствие успешного лога N часов (dead man’s switch).
Автоматизация — это не «написал 20 строк». Это повторяемый результат + сигнал, когда сломалось 📡