Инструменты пользователя

Инструменты сайта


projects:linux:backups

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
projects:linux:backups [2025/03/28 12:48] projects:linux:backups [2025/03/30 00:17] (текущий) – [Основной скрипт]
Строка 1: Строка 1:
-===== Создание резервной копии SD карты =====+====== Создание резервной копии SD карты ====== 
 + 
 +=====Основной скрипт=====
  
 ++++Скрипт создания резервной копии SD карты на USB носитель| ++++Скрипт создания резервной копии SD карты на USB носитель|
-<file bash backup_sd.sh>+<code bash sd_backup.sh>
 #!/bin/bash #!/bin/bash
 +export LANG=C.UTF-8
 # ==AUTOEXEC== # ==AUTOEXEC==
-# === Резервирование SD === +# === SD BackUp === 
-Резервирование SD карты с остановкой wireguard +# Резервное копирование SD карты 
-и перезапуском после окончания +Расширенный скрипт резервного копирования SD 
-# * в локальной сети wireguard останавливается и +с автоустановкой зависимостейлогированием и CLI-интерфейсом 
-# * запускается резервное копирование +#
-* копия после создания сжимается (или нетпо выбору), в имени указывается +
-# * комментарий запрошенный при запуске скрипта+
  
-export LANG=en_US.UTF-8 +VERSION="1.2" 
-export LC_ALL=en_US.UTF-8+SCRIPT_NAME="backup-sd"
  
-=== Самозащитазапускаем теневую копию === +if [[ "$1" == "--help" || "$1" == "-h" ]]; then 
-if [[ "$0" ="$BASH_SOURCE&& -"$_SAFE_BACKUP_CLONE]]; then +  echo "📘 Использование$SCRIPT_NAME [опции]" 
-  TMP_CLONE=$(mktemp /tmp/safe-backup-XXXXXX.sh) +  echo 
-  cp "$0" "$TMP_CLONE+  echo "Опции:" 
-  chmod +x "$TMP_CLONE+  echo "  --comment=…           Комментарий для имени файла" 
-  echo "🚨 Запуск временной копии: $TMP_CLONE+  echo  --compress=TYPE       Сжатие: gzip, xz, zstd, none" 
-  _SAFE_BACKUP_CLONE=1 exec "$TMP_CLONE" "$@"+  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 fi
  
-# Путь к папке для бэкапов на SSD +if [[ "$1" == "--version]]; then 
-BACKUP_DIR="/mnt/backup" +  echo "$SCRIPT_NAME v$VERSION"
-# Устройство SD-карты (проверьте имя командой lsblk) +
-SD_CARD="/dev/mmcblk0" +
-# Текущая дата и время для формирования имени файла +
-DATE=$(date +"%Y-%m-%d_%H-%M-%S"+
- +
-# Меню выбора действия +
-echo "=== Меню ===" +
-echo "1. Создать резервную копию (сжать gzip)" +
-echo "2. Создать резервную копию (без сжатия)" +
-echo "0. Выход" +
-echo "Введите номер действия:" +
-read CHOICE +
- +
-if [ "$CHOICE" == "0" ]; then +
-  echo "🚪 Выход из скрипта."+
   exit 0   exit 0
 fi fi
  
-if [ "$CHOICE" != "1" ] && "$CHOICE" != "2" ]; then +# Определение директории логов 
-  echo "❌ Неверный выбор. Выход.+if [[ -d /mnt/usb ]]; then 
-  exit 1+  LOG_DIR="/mnt/usb/logs/backup" 
 +elif [[ -d /tmp ]]; then 
 +  LOG_DIR="/tmp/backup-logs" 
 +else 
 +  LOG_DIR="/var/log/backup"
 fi fi
 +mkdir -p "$LOG_DIR"
  
-# Запрос комментария у пользователя +log() { 
-echo "Введите комментарий к резервной копии (или оставьте пустым):+  echo "[$(date +'%F %T')] $1" | tee -a "$LOG_DIR/backup.log
-read COMMENT+}
  
-if [ -"$COMMENT" ]; then +# ... остальной скрипт будет дополнен ниже 
-    COMMENT="Без комментария"+ 
 +# Параметры и аргументы 
 +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 -"$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 fi
  
-# Функция транслитерации кириллицы +if [[ -f "$CONFIG_FILE" ]]; then 
-transliterate() { +  source "$CONFIG_FILE" 
-    echo "$1| sed -e 's/а/a/g' -e 's/б/b/g' -e 's/в/v/g' -e 's/г/g/g' \ +  if [[ "$use_config== "true" ]]; then 
-                    -e 's/д/d/g' -e 's/е/e/g' -e 's/ё/e/g' -e 's/ж/zh/g'+    log "📝 Используем параметры из конфигайла $CONFIG_FILE" 
-                    -e 's/з/z/g' -e 's/и/i/g' -e 's/й/j/g' -e 's/к/k/g'+    USE_CONFIG=true 
-                    -e 's/л/l/g' -e 's/м/m/g' -e 's/н/n/g' -e 's/о/o/g'+  fi 
-                    -e 's/п/p/g' -e 's/р/r/g' -e 's/с/s/g' -e 's/т/t/g' \ +fi
-                    -e 's/у/u/g' -e 's/ф/f/g' -e 's/х/h/g' -e 's/ц/ts/g' \ +
-                    -e 's/ч/ch/g' -e 's/ш/sh/g' -e 's/щ/shch/g' -e 's/ъ/_/g' \ +
-                    -e 's/ы/y/g' -e 's/ь/_/g' -e 's/э/e/g' -e 's/ю/yu/g'+
-                    -e 's/я/ya/g' -e 's/А/A/g' -e 's/Б/B/g' -e 's/В/V/g'+
-                    -e 's/Г/G/g' -e 's/Д/D/g' -e 's/Е/E/g' -e 's/Ё/E/g'+
-                    -e 's/Ж/ZH/g' -e 's/З/Z/g' -e 's/И/I/g' -e 's/Й/J/g'+
-                    -e 's/К/K/g' -e 's/Л/L/g' -e 's/М/M/g' -e 's/Н/N/g'+
-                    -e 's/О/O/g' -e 's/П/P/g' -e 's/Р/R/g' -e 's/С/S/g'+
-                    -e 's/Т/T/g' -e 's/У/U/g' -e 's/Ф/F/g' -e 's/Х/H/g'+
-                    -e 's/Ц/TS/g' -e 's/Ч/CH/g' -e 's/Ш/SH/g' -e 's/Щ/SHCH/g'+
-                    -e 's/Ъ/_/g' -e 's/Ы/Y/g' -e 's/Ь/_/g' -e 's/Э/E/g'+
-                    -e 's/Ю/YU/g' -e 's/Я/YA/g' | tr ' ' '_' | tr -cd '[:alnum:]_' +
-}+
  
-# Очистка комментария перед транслитерацией для имени файла +if [[ "$USE_CONFIG" == "false" ]]; then 
-CLEAN_COMMENT=$(echo "$COMMENT| iconv -f utf-8 -t utf-8 -c | tr -cd '[:alnum:]а-яА-ЯёЁ .,()_+-' | sed 's/[[:space:]]\+/ /g' | xargs) +  backup_dir="/mnt/backup" 
-SAFE_COMMENT=$(transliterate "$CLEAN_COMMENT")+  temp_dir="/mnt/backup/tmp" 
 +  sd_card="/dev/mmcblk0" 
 +  comment="Резервная копия" 
 +  compression="gzip
 +  shrink=true 
 +  sha256=true 
 +fi
  
-# Формирование имени файла бэкапа +if [[ "$NON_INTERACTIVE" == false ]]; then 
-EXT="img+  echo "=== Меню резервного копирования ===" 
-if [ "$CHOICE" == "1]then +  echo "1. Снимок - dd + gzip" 
-  EXT="img.gz"+  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 fi
-BACKUP_FILE="$BACKUP_DIR/backup_${DATE}_${SAFE_COMMENT}.$EXT" 
  
-# Проверка, что папка для бэкапов существует +mkdir -p "$backup_dir" "$temp_dir" 
-if [ -"$BACKUP_DIR" ]; then + 
-    echo шибка: папка $BACKUP_DIR не найдена! Проверьте, смонтирован ли SSD.+if [-"$source_img]]; then 
-    exit 1+  log "🔕 Отключаем системное логирование на время копирования
 +  sudo systemctl stop systemd-journald.socket 
 +  sudo systemctl stop systemd-journald.service
 fi fi
  
-# Определение IP клиента и проверка на WireGuard-подсеть +date_now=$(date +"%Y-%m-%d_%H-%M-%S") 
-CLIENT_IP=$(who am i awk '{print $5}' | grep -oE '[0-9.]+') +comment_safe=$(echo "$comment" tr ' '_' | tr -cd '[:alnum:]_') 
-if [[ "$CLIENT_IP=~ ^10\. ]]; then +basename=${TEMPLATE:-backup_%DATE%_%COMMENT%} 
-    echo "⚠️ Обнаружено подключение по WireGuard ($CLIENT_IP) — не отключаем wg-quick@wg0+basename=$(echo "$basename" | sed "s/%DATE%/$date_now/g" | sed "s/%COMMENT%/$comment_safe/g" | cut -c1-100) 
-    WG_SKIP=1+img_file="$temp_dir/${basename}.img" 
 + 
 +if [[ -n "$source_img" ]]; then 
 +  log "📂 Используем существующий файл: $source_img
 +  img_file="$source_img"
 else else
-    echo "⏸️ Останавливаем WireGuard (wg-quick@wg0)...+  log "💾 Создаём образ SD: $img_file
-    sudo systemctl stop wg-quick@wg0 +  sudo dd if="$sd_card" bs=4M status=progress of="$img_file"
-    WG_STOPPED=1+
 fi fi
  
-# Сброс буферов перед резервным копированием +if [[ ! -f "$img_file" ]]; then log "❌ Файл не найден: $img_file"; exit 1; fi
-echo "💾 Сброс буферов на диск..." +
-sync+
  
-# Получение общего размера устройства +if [[ "$shrink" == "true" ]]; then 
-SD_SIZE=$(sudo blockdev --getsize64 "$SD_CARD" 2>/dev/null || echo 0) +  log "🔧 Уменьшение через pishrink.sh..." 
-HUMAN_SIZE=$(numfmt --to=iec $SD_SIZE) +  [[ ! -x ./pishrink.sh ]] && wget -q https://raw.githubusercontent.com/Drewsif/pishrink/master/pishrink.sh -O ./pishrink.sh && chmod +x ./pishrink.sh 
-echo "📦 Ожидаемый общий размер: $HUMAN_SIZE" +  keep_flag="" 
-ESTIMATED_MIN=$(numfmt --to=iec $((SD_SIZE * 30 / 100))) +  [[ "$KEEP_IMG" == true ]] && keep_flag="-k" 
-ESTIMATED_MAX=$(numfmt --to=iec $((SD_SIZE * 70 / 100))) +  sudo ./pishrink.sh $keep_flag "$img_file" 
-echo "🧮 После сжатия ожидаемый размер архива: от $ESTIMATED_MIN до $ESTIMATED_MAX"+fi
  
-# Резервное копирование через dd с отображением прогресса +final_file="$img_file" 
-echo "📋 Копирование с помощью dd..." + 
-if [ "$CHOICE" == "1" ]; then +if [[ "$compression" == "gzip" ]]; then 
-  sudo dd if=$SD_CARD bs=4M status=progress | gzip > "$BACKUP_FILE+  log "📦 Сжатие gzip..." 
-else +  command -v pigz &>/dev/null && pigz -9 "$final_file" || gzip -9 "$final_file" 
-  sudo dd if=$SD_CARD bs=4M status=progress of="$BACKUP_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 fi
  
-echo "✅ Чтение завершено."+[[ $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
  
-# Запуск WireGuard после резервного копирования (если мы его останавливали) +if [[ "$sha256" == "true" ]]; then 
-if [[ "$WG_STOPPED" == "1" ]]; then +  log "🔐 SHA256-сумма..." 
-    echo "▶️ Запускаем WireGuard обратно..." +  sha256_value=$(sha256sum "$final_file"
-    sudo systemctl start wg-quick@wg0+  echo "$sha256_value" > "$final_file.sha256"
 fi 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"
-echo -e "$DATE - $COMMENT" | iconv -f utf-8 -t utf-8 -c tee -a "$BACKUP_DIR/backup_log.txt" > /dev/null+
  
-# Вывод размера итогового файла +final_dest="$backup_dir/$(basename "$final_file")" 
-FILE_SIZE=$(du -h "$BACKUP_FILE| cut -f1+log "📁 Перемещаем результат в каталог: $backup_dir" 
-echo "📦 Размер резервной копии: $FILE_SIZE"+mv "$final_file" "$final_dest" 
 +[[ "$sha256" == "true" && -f "$final_file.sha256" ]] && mv "$final_file.sha256" "$final_dest.sha256"
  
-# Создание контрольной суммы SHA256 +log "🎉 Готово$final_dest"
-SHA_FILE="$BACKUP_FILE.sha256" +
-echo "🔐 Создаём контрольную сумму SHA256..." +
-sha256sum "$BACKUP_FILE" | tee "$SHA_FILE"+
  
-echo "🎉 Резервное копирование завершено полностью!" +if [[ -z "$source_img" ]]; then 
-echo "✅ Резервная копия: $BACKUP_FILE" +  log "🔔 Включаем обратно системное логирование" 
-echo "🔐 Контрольная сумма сохранена: $SHA_FILE"+  sudo systemctl start systemd-journald.socket 
 +  sudo systemctl start systemd-journald.service 
 +fi 
 + 
 +exit 0
  
-</file>+++++</code>++++
  
 ===== MarkDown ===== ===== MarkDown =====
Строка 163: Строка 237:
 ## 📦 Поддерживаемые аргументы ## 📦 Поддерживаемые аргументы
  
-^ Аргумент                   ^ Значение / Описание                          ^ Пример                                +^ Аргумент                       ^ Значение / Описание                          ^ Пример                                  
-| ''--comment=...''          | Комментарий для имени файла                  | ''--comment="ежедневный"''              | +| ''--comment=...''              | Комментарий для имени файла                  | ''--comment="ежедневный"''              | 
-| ''--compress=gzip''        | Метод сжатия: `gzip`, `xz`, `zstd`, `none`   | ''--compress=zstd''                     | +| ''--compress=gzip''            | Метод сжатия: `gzip`, `xz`, `zstd`, `none`   | ''--compress=zstd''                     | 
-| ''--shrink''               | Включить уменьшение образа (shrink)          | ''--shrink''                            | +| ''--shrink''                   | Включить уменьшение образа (shrink)          | ''--shrink''                            | 
-| ''--no-shrink''            | Не уменьшать образ                           | ''--no-shrink''                         | +| ''--no-shrink''                | Не уменьшать образ                           | ''--no-shrink''                         | 
-| ''--sha256''               | Посчитать SHA256                             | ''--sha256''                            | +| ''--sha256''                   | Посчитать SHA256                             | ''--sha256''                            | 
-| ''--no-sha256''            | Не считать SHA256                            | ''--no-sha256''                         | +| ''--no-sha256''                | Не считать SHA256                            | ''--no-sha256''                         | 
-| ''--device=/dev/...''        | Устройство для копирования                   | ''--device=/dev/mmcblk0''               | +| ''--device=/dev/...''          | Устройство для копирования                   | ''--device=/dev/mmcblk0''               | 
-| ''--source=/path/to.img''    | Использовать готовый `.img`, не делать `dd`  | ''--source=/mnt/usb/backup.img''        | +| ''--source=/path/to.img''      | Использовать готовый `.img`, не делать `dd`  | ''--source=/mnt/usb/backup.img''        | 
-| ''--keep-img''               | Не удалять `.img` после shrink               | ''--keep-img''                          | +| ''--keep-img''                 | Не удалять `.img` после shrink               | ''--keep-img''                          | 
-| ''--keep-days=N''            | Удалять копии старше N дней                  | ''--keep-days=7''                       | +| ''--keep-days=N''              | Удалять копии старше N дней                  | ''--keep-days=7''                       | 
-| ''--keep-count=N''           | Хранить не более N последних копий           | ''--keep-count=3''                      | +| ''--keep-count=N''             | Хранить не более N последних копий           | ''--keep-count=3''                      | 
-| ''--log=/path/to.log''      | Путь к лог-файлу                             | ''--log=/mnt/usb/backup.log''           | +| ''--log=/path/to.log''         | Путь к лог-файлу                             | ''--log=/mnt/usb/backup.log''           | 
-| ''--template=ШАБЛОН''       | Шаблон имени файла: `%DATE%`, `%COMMENT%`    | ''-template="wash_%DATE%_%COMMENT%"''   +| ''--template=ШАБЛОН''          | Шаблон имени файла: `%DATE%`, `%COMMENT%`    | ''--template="wash_%DATE%_%COMMENT%"''  | 
-| ''-n`, ''--non-interactive''  | Без меню, полностью через параметры          | ''--non-interactive''                   | +| ''-n'', ''--non-interactive''  | Без меню, полностью через параметры          | ''--non-interactive''                   | 
-| ''-y'', `--auto-install`     | Автоустановка зависимостей                   | ''--auto-install''                      |+| ''-y'', `--auto-install`       | Автоустановка зависимостей                   | ''--auto-install''                      |
 | ''-h'', ''--help''             | Показать справку                             | ''--help''                              | | ''-h'', ''--help''             | Показать справку                             | ''--help''                              |
-| ''--version''                | Показать версию скрипта                      | ''--version''                           |+| ''--version''                  | Показать версию скрипта                      | ''--version''                           |
  
 --- ---
  
-## 🧪 Примеры запуска+===== 🧪 Примеры запуска =====
  
-### 📦 Съём и сжатие: +📦 Съём и сжатие: 
-```bash+ 
 +<code bash>
 ./backup-sd.sh --comment="ночной" --compress=zstd --shrink --sha256 --device=/dev/mmcblk0 -n ./backup-sd.sh --comment="ночной" --compress=zstd --shrink --sha256 --device=/dev/mmcblk0 -n
-```+</code> 
  
-### 🗃️ Обработка существующего `.img`, shrink + gzip: +🗃️ Обработка существующего `.img`, shrink + gzip: 
-```bash+<code bash>
 ./backup-sd.sh --source=/mnt/usb/old.img --compress=gzip --shrink --comment="старый образ" --keep-img -n ./backup-sd.sh --source=/mnt/usb/old.img --compress=gzip --shrink --comment="старый образ" --keep-img -n
-```+</code>
  
-### ♻️ Просто сжать `.img`, без shrink: +♻️ Просто сжать `.img`, без shrink: 
-```bash+<code bash>
 ./backup-sd.sh --source=image.img --compress=zstd --no-shrink --comment="просто сжали" -n ./backup-sd.sh --source=image.img --compress=zstd --no-shrink --comment="просто сжали" -n
-```+</code>
  
 --- ---
  
-## 📝 Замечания+📝 Замечания
  
-- Поддерживает `shrinkчерез встроенный `pishrink.sh`, загружаемый при необходимости. +  - Поддерживает ''shrink'' (сокращение размера img за счет удаления пространства без данных) через встроенный ''pishrink.sh'', загружаемый при необходимости. 
-- Все параметры можно комбинировать. +  - Все параметры можно комбинировать. 
-- Подходит для cron, systemd, ручных задач и GUI-обёрток.+  - Подходит для cron, systemd, ручных задач и GUI-обёрток.
  
projects/linux/backups.1743155305.txt.gz · Последнее изменение: 2025/03/28 12:48 —

Если не указано иное, содержимое этой вики предоставляется на условиях следующей лицензии: CC Attribution 4.0 International
CC Attribution 4.0 International Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki