Создание резервной копии SD карты
Основной скрипт
Скрипт создания резервной копии SD карты на USB носитель
- sd_backup.sh
#!/bin/bash
export LANG=C.UTF-8
# ==AUTOEXEC==
# === SD BackUp ===
# Резервное копирование SD карты
# Расширенный скрипт резервного копирования SD
# с автоустановкой зависимостей, логированием и CLI-интерфейсом
#
VERSION="1.2"
SCRIPT_NAME="backup-sd"
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
echo "📘 Использование: $SCRIPT_NAME [опции]"
echo
echo "Опции:"
echo " --comment=… Комментарий для имени файла"
echo " --compress=TYPE Сжатие: gzip, xz, zstd, none"
echo " --shrink / --no-shrink Уменьшить образ / не уменьшать"
echo " --sha256 / --no-sha256 Хэш SHA256 / не считать"
echo " --device=/dev/… Устройство (например, /dev/mmcblk0)"
echo " --source=/path.img Использовать готовый образ"
echo " --keep-img Не удалять .img после shrink"
echo " --keep-days=N Удалить копии старше N дней"
echo " --keep-count=N Хранить не более N копий"
echo " --log=/path.log Путь к лог-файлу"
echo " --template=ШАБЛОН Имя: %DATE%, %COMMENT%"
echo " -n / --non-interactive Без меню (только аргументы)"
echo " -y / --auto-install Установить зависимости"
echo " -h / --help Показать эту справку"
echo " --version Показать версию скрипта"
exit 0
fi
if [[ "$1" == "--version" ]]; then
echo "$SCRIPT_NAME v$VERSION"
exit 0
fi
# Определение директории логов
if [[ -d /mnt/usb ]]; then
LOG_DIR="/mnt/usb/logs/backup"
elif [[ -d /tmp ]]; then
LOG_DIR="/tmp/backup-logs"
else
LOG_DIR="/var/log/backup"
fi
mkdir -p "$LOG_DIR"
log() {
echo "[$(date +'%F %T')] $1" | tee -a "$LOG_DIR/backup.log"
}
# ... остальной скрипт будет дополнен ниже
# Параметры и аргументы
CONFIG_FILE="./backup.conf"
USE_CONFIG=false
REQUIRED_CMDS=(dd gzip xz zstd losetup parted e2fsck resize2fs tune2fs kpartx mount sha256sum)
INSTALL=false
NON_INTERACTIVE=false
KEEP_DAYS=0
KEEP_COUNT=0
TEMPLATE=""
KEEP_IMG=false
source_img=""
for arg in "$@"; do
case $arg in
--comment=*) comment="${arg#*=}" ;;
--compress=*) compression="${arg#*=}" ;;
--shrink) shrink=true ;;
--no-shrink) shrink=false ;;
--sha256) sha256=true ;;
--no-sha256) sha256=false ;;
--device=*) sd_card="${arg#*=}" ;;
--keep-days=*) KEEP_DAYS="${arg#*=}" ;;
--keep-count=*) KEEP_COUNT="${arg#*=}" ;;
--log=*) LOG_FILE="${arg#*=}" ;;
--template=*) TEMPLATE="${arg#*=}" ;;
--keep-img) KEEP_IMG=true ;;
--source=*) source_img="${arg#*=}" ;;
-n|--non-interactive) NON_INTERACTIVE=true ;;
-y|--auto-install) INSTALL=true ;;
esac
done
if $INSTALL; then
MISSING=()
for cmd in "${REQUIRED_CMDS[@]}"; do
if ! command -v "$cmd" &>/dev/null; then MISSING+=("$cmd"); fi
done
if [[ ${#MISSING[@]} -gt 0 ]]; then
log "📦 Устанавливаю зависимости: ${MISSING[*]}"
sudo apt-get update -y && sudo apt-get install -y "${MISSING[@]}"
else
log "✅ Все зависимости уже установлены."
fi
fi
if [[ -f "$CONFIG_FILE" ]]; then
source "$CONFIG_FILE"
if [[ "$use_config" == "true" ]]; then
log "📝 Используем параметры из конфиг-файла $CONFIG_FILE"
USE_CONFIG=true
fi
fi
if [[ "$USE_CONFIG" == "false" ]]; then
backup_dir="/mnt/backup"
temp_dir="/mnt/backup/tmp"
sd_card="/dev/mmcblk0"
comment="Резервная копия"
compression="gzip"
shrink=true
sha256=true
fi
if [[ "$NON_INTERACTIVE" == false ]]; then
echo "=== Меню резервного копирования ==="
echo "1. Снимок - dd + gzip"
echo "2. Снимок - dd без сжатия"
echo "3. Снимок - dd + shrink"
echo "4. Снимок - dd + shrink + gzip"
echo "5. Снимок - dd + shrink + xz"
echo "6. Уменьшить существующий образ"
echo "7. Уменьшить и сжать существующий образ (gzip)"
echo "8. Уменьшить и сжать существующий образ (zstd)"
echo "0. Выход"
read -p "Выберите режим: " CHOICE
case "$CHOICE" in
1) compression="gzip"; shrink=false;;
2) compression="none"; shrink=false;;
3) compression="none"; shrink=true;;
4) compression="gzip"; shrink=true;;
5) compression="xz"; shrink=true;;
6) read -p "Путь к существующему .img: " source_img; shrink=true; compression="none";;
7) read -p "Путь к существующему .img: " source_img; shrink=true; compression="gzip";;
8) read -p "Путь к существующему .img: " source_img; shrink=true; compression="zstd";;
0) echo "🚪 Выход"; exit 0;;
*) echo "❌ Неверный выбор"; exit 1;;
esac
[[ -z "$source_img" ]] && read -p "Комментарий к резервной копии: " comment
fi
mkdir -p "$backup_dir" "$temp_dir"
if [[ -z "$source_img" ]]; then
log "🔕 Отключаем системное логирование на время копирования"
sudo systemctl stop systemd-journald.socket
sudo systemctl stop systemd-journald.service
fi
date_now=$(date +"%Y-%m-%d_%H-%M-%S")
comment_safe=$(echo "$comment" | tr ' ' '_' | tr -cd '[:alnum:]_')
basename=${TEMPLATE:-backup_%DATE%_%COMMENT%}
basename=$(echo "$basename" | sed "s/%DATE%/$date_now/g" | sed "s/%COMMENT%/$comment_safe/g" | cut -c1-100)
img_file="$temp_dir/${basename}.img"
if [[ -n "$source_img" ]]; then
log "📂 Используем существующий файл: $source_img"
img_file="$source_img"
else
log "💾 Создаём образ SD: $img_file"
sudo dd if="$sd_card" bs=4M status=progress of="$img_file"
fi
if [[ ! -f "$img_file" ]]; then log "❌ Файл не найден: $img_file"; exit 1; fi
if [[ "$shrink" == "true" ]]; then
log "🔧 Уменьшение через pishrink.sh..."
[[ ! -x ./pishrink.sh ]] && wget -q https://raw.githubusercontent.com/Drewsif/pishrink/master/pishrink.sh -O ./pishrink.sh && chmod +x ./pishrink.sh
keep_flag=""
[[ "$KEEP_IMG" == true ]] && keep_flag="-k"
sudo ./pishrink.sh $keep_flag "$img_file"
fi
final_file="$img_file"
if [[ "$compression" == "gzip" ]]; then
log "📦 Сжатие gzip..."
command -v pigz &>/dev/null && pigz -9 "$final_file" || gzip -9 "$final_file"
final_file="${final_file}.gz"
elif [[ "$compression" == "xz" ]]; then
log "📦 Сжатие xz..."
xz -T0 -z "$final_file"
final_file="${final_file}.xz"
elif [[ "$compression" == "zstd" ]]; then
log "📦 Сжатие zstd..."
zstd -19 -T0 "$final_file"
final_file="${final_file}.zst"
fi
[[ $KEEP_DAYS -gt 0 ]] && find "$backup_dir" -name "backup_*.img*" -type f -mtime +$KEEP_DAYS -exec rm -v {} +
[[ $KEEP_COUNT -gt 0 ]] && ls -tp "$backup_dir"/backup_*.img* 2>/dev/null | grep -v '/$' | tail -n +$((KEEP_COUNT + 1)) | xargs -r rm -v
if [[ "$sha256" == "true" ]]; then
log "🔐 SHA256-сумма..."
sha256_value=$(sha256sum "$final_file")
echo "$sha256_value" > "$final_file.sha256"
fi
[[ -n "$LOG_FILE" ]] && echo "[$(date +'%F %T')] File: $final_file | Size: $(du -h "$final_file" | cut -f1) | SHA: $(echo "$sha256_value" | cut -d ' ' -f1)" >> "$LOG_FILE"
final_dest="$backup_dir/$(basename "$final_file")"
log "📁 Перемещаем результат в каталог: $backup_dir"
mv "$final_file" "$final_dest"
[[ "$sha256" == "true" && -f "$final_file.sha256" ]] && mv "$final_file.sha256" "$final_dest.sha256"
log "🎉 Готово: $final_dest"
if [[ -z "$source_img" ]]; then
log "🔔 Включаем обратно системное логирование"
sudo systemctl start systemd-journald.socket
sudo systemctl start systemd-journald.service
fi
exit 0
MarkDown
# Скрипт `backup-sd.sh`
Расширенный скрипт резервного копирования SD-карт с поддержкой shrink, сжатия, логирования и CLI-интерфейса. Подходит для автоматизации задач резервного копирования на Raspberry Pi и аналогичных устройствах.
—
## 📦 Поддерживаемые аргументы
Аргумент | Значение / Описание | Пример |
–comment=… | Комментарий для имени файла | –comment=«ежедневный» |
–compress=gzip | Метод сжатия: `gzip`, `xz`, `zstd`, `none` | –compress=zstd |
–shrink | Включить уменьшение образа (shrink) | –shrink |
–no-shrink | Не уменьшать образ | –no-shrink |
–sha256 | Посчитать SHA256 | –sha256 |
–no-sha256 | Не считать SHA256 | –no-sha256 |
–device=/dev/… | Устройство для копирования | –device=/dev/mmcblk0 |
–source=/path/to.img | Использовать готовый `.img`, не делать `dd` | –source=/mnt/usb/backup.img |
–keep-img | Не удалять `.img` после shrink | –keep-img |
–keep-days=N | Удалять копии старше N дней | –keep-days=7 |
–keep-count=N | Хранить не более N последних копий | –keep-count=3 |
–log=/path/to.log | Путь к лог-файлу | –log=/mnt/usb/backup.log |
–template=ШАБЛОН | Шаблон имени файла: `%DATE%`, `%COMMENT%` | –template=«wash_%DATE%_%COMMENT%» |
-n , –non-interactive | Без меню, полностью через параметры | –non-interactive |
-y , `–auto-install` | Автоустановка зависимостей | –auto-install |
-h , –help | Показать справку | –help |
–version | Показать версию скрипта | –version |
—
🧪 Примеры запуска
📦 Съём и сжатие:
./backup-sd.sh --comment="ночной" --compress=zstd --shrink --sha256 --device=/dev/mmcblk0 -n
🗃️ Обработка существующего `.img`, shrink + gzip:
./backup-sd.sh --source=/mnt/usb/old.img --compress=gzip --shrink --comment="старый образ" --keep-img -n
♻️ Просто сжать `.img`, без shrink:
./backup-sd.sh --source=image.img --compress=zstd --no-shrink --comment="просто сжали" -n
—
📝 Замечания
Поддерживает shrink
(сокращение размера img за счет удаления пространства без данных) через встроенный pishrink.sh
, загружаемый при необходимости.
Все параметры можно комбинировать.
Подходит для cron, systemd, ручных задач и
GUI-обёрток.