Разбить большое дерево каталогов на куски указанного размера?

11

У меня есть дерево каталогов, которое я хотел бы сделать резервную копию на оптических дисках. К сожалению, он превышает размер любого диска (около 60 ГБ). Я ищу сценарий, который разбил бы это дерево на куски соответствующего размера с жесткими ссылками или еще чем-нибудь (оставив оригинал нетронутым). Затем я мог бы передать эти деревья размером с кусочек в процесс резервного копирования (добавить избыточность PAR2 и т. Д.).

Это не причудливый сценарий, но кажется, что это уже было сделано. Предложения?

(Наращивание и запись за один шаг не нужны, потому что я хочу сделать больше вещей, прежде чем файлы будут записаны.)

Reid
источник
Рассматривали ли вы получить синюшного писателя?
BSD
2
Носители DVD ненадежны ... Я бы порекомендовал внешний накопитель, резервное копирование в онлайн-хранилище, например, Carbonite, или, если записывающий носитель, используйте некоторую par2защиту.
Аарон Д. Мараско

Ответы:

7

Существует приложение, предназначенное для этого: dirsplit

Это обычно живет cdrkitили dirsplitпакеты.

Он может создавать готовые к использованию папки со ссылками, чтобы легко создавать DVD-диски с K3b или другим программным обеспечением GUI

Хьюберт Карио
источник
Это сработало очень хорошо. В Ubuntu я нашел это в genisoimageпакете.
nograpes
2

Однажды я сделал уродливый сценарий для аналогичной цели. Это просто клочок, но когда я его написал, меня не волновало время выполнения или красивость. Я уверен, что есть более «продуктивные» версии одной и той же концепции, но если вы хотите получить какие-то идеи или что-то, чтобы начать взламывать, вот так (сделал это в 2008 году, так что используйте на свой страх и риск!): - )

#!/bin/sh -
REPO=/export/foton/PictureStore
LINKS=/export/foton/links
SPLITTIX=`date '+%y%m%d-%H%M'`

# kilobytes
DVDSIZE=4400000
PARTPREFIX="DVD-"
REPOSIZE=`du -sk -- ${REPO} | awk '{print $1}'`
NUMPARTS=`expr $REPOSIZE / $DVDSIZE`
SPLITDIR=${LINKS}/splits/${SPLITTIX}
mkdir -p -- "$SPLITDIR"

PARTNUM=1
PARTSIZ=0
DONESIZ=0
PARTNUM=`echo $PARTNUM | awk '{printf("%03x", $0)}'`
mkdir -p -- "${SPLITDIR}/${PARTPREFIX}${PARTNUM}"
for D in "${REPO}"/..?* "${REPO}"/.[!.]* "${REPO}"/*
do
  if [ ! -e "$D" ]; then continue; fi  # skip ..?*, .[!.]* and * if there are no matching files
  D=${D#$REPO/}
  D_SIZ=`du -sk -- "${REPO}/$D" | awk '{print $1}'`
  if test `expr $D_SIZ + $PARTSIZ` -le $DVDSIZE
  then
    # link to D in this part
    ln -s -- "$REPO/$D" "${SPLITDIR}/${PARTPREFIX}${PARTNUM}/$D"
    # adjust counters
    PARTSIZ=`expr $PARTSIZ + $D_SIZ`
    DONESIZ=`expr $DONESIZ + $D_SIZ`
  else
    # next part and link to D in that
    echo PART $PARTNUM: $PARTSIZ kb '(target' $DVDSIZE 'kb)'
    PARTNUM=`expr $PARTNUM + 1`
    PARTNUM=`echo $PARTNUM | awk '{printf("%03x", $0)}'`
    PARTSIZ=$D_SIZ
    DONESIZ=`expr $DONESIZ + $D_SIZ`
    mkdir -p -- "${SPLITDIR}/${PARTPREFIX}${PARTNUM}"
    ln -s -- "$REPO/$D" "${SPLITDIR}/${PARTPREFIX}${PARTNUM}/$D"
  fi
done
echo "wrote $DONESIZ kb in $PARTNUM parts in $SPLITDIR"

Я думаю, что я получил результат через samba для хоста Windows, который записывал с него диски. Если вы используете вышеизложенное без изменений, вы можете использовать mkisofsдругой архиватор, который разрешает символические ссылки.

MattBianco
источник
Я сделал несколько изменений в вашем скрипте, чтобы справиться со специальными символами в именах файлов (пробел, начальные тире и точки \[?*). Рекомендуемое чтение: не анализируйте вывод ls , $ VAR vs $ {VAR} и заключать в кавычки или не заключать в кавычки . Обратите внимание, что я не проверял полученный скрипт. Если вы не понимаете мои изменения, не стесняйтесь спрашивать.
Жиль "ТАК - перестань быть злым"
@ Жиль: я много читал с 2008 года ;-) Хороши изменения, чтобы сделать сценарий более общим. (Мне не нравится введение, [в отличие от test, хотя) ...
MattBianco
Вы должны в нижнем регистре большинство из этих переменных. По соглашению мы используем заглавные переменные среды (PAGER, EDITOR, SHELL, ...) и переменные внутренней оболочки. Все остальные имена переменных должны содержать хотя бы одну строчную букву. Это соглашение позволяет избежать случайного переопределения внешних и внутренних переменных.
Крис Даун
2

Однажды я написал скрипт для решения аналогичной проблемы - я назвал его «распространять» (вы можете прочитать основной код скрипта или файл с помощью сообщения помощи или загрузить его в виде пакета ); из его описания :

распространять - распространять коллекцию пакетов на нескольких компакт-дисках (особенно хорошо для будущего использования с APT)

Описание: программа `распространять 'облегчает выполнение задач, связанных с созданием набора компакт-дисков для распространения набора пакетов. Задачи включают в себя: разметку файловой системы CD (разделение большого количества пакетов на несколько дисков и т. Д.), Подготовку коллекции для использования APT (индексация), создание образов ISO и запись дисков.

Периодические обновления первоначально распределенной коллекции могут быть выпущены с помощью `распространять '.

Он выполняет весь процесс в несколько этапов: на одном этапе он создает «раскладки» будущего диска с помощью символических ссылок на исходные файлы - так что вы можете вмешиваться и изменять будущие деревья дисков.

Подробно о его использовании можно прочитать в справочном сообщении, напечатанном скриптом (или заглянув в исходный код).

Он был написан с учетом более сложного варианта использования (выпуск обновлений в виде «diff» - набора добавленных новых файлов - к первоначально записанному набору файлов), поэтому он включает один дополнительный начальный этап, а именно «исправление» «текущее состояние коллекции файлов (для простоты она делает это путем репликации исходной коллекции файлов с помощью символических ссылок, в специальном рабочем месте для сохранения состояний коллекции; затем, когда-нибудь в будущем, сможет создать разницу между будущим текущим состоянием коллекции файлов и этим сохраненным состоянием). Таким образом, хотя вам может не понадобиться эта функция, вы не можете пропустить этот начальный этап, AFAIR.

Кроме того, я не уверен сейчас (я написал это несколько лет назад), хорошо ли он обрабатывает сложные деревья, или он должен разделять только простые (один уровень) каталоги файлов. (Пожалуйста, посмотрите сообщение справки или исходный код, чтобы быть уверенным; я тоже посмотрю это чуть позже, когда у меня будет время.)

Материал, связанный с APT, является необязательным, поэтому не обращайте внимания на то, что он может подготовить наборы пакетов для использования APT, если вам это не нужно.

Если вам интересно, конечно, не стесняйтесь переписать его в соответствии с вашими потребностями или предложить улучшения.

(Обратите внимание, что в пакет включены дополнительные полезные патчи, не примененные в представленном списке кодов в репозитории Git, указанном выше!)

imz - Иван Захарящев
источник
Я представил - среди прочего - фрагмент кода, distributeкоторый решает основную задачу, о которой здесь говорится .
imz - Иван Захарящев
2

Мы не должны забывать, что суть задачи действительно довольно проста; как положено в учебнике по Haskell (который написан вокруг проработки решения для этой задачи, постепенно улучшается)

Теперь давайте немного подумаем о том, как будет работать наша программа, и выразим ее в псевдокоде:

main = Read list of directories and their sizes.
       Decide how to fit them on CD-Rs.
       Print solution.

Звучит разумно? Я так думала.

Давайте немного упростим нашу жизнь и пока предположим, что мы будем вычислять размеры каталогов где-то за пределами нашей программы (например, с помощью " du -sb *") и читать эту информацию из stdin.

(из путеводителя автостопом по Хаскеллу, глава 1 )

(Кроме того, в вашем вопросе вы хотели бы иметь возможность настроить (отредактировать) полученные макеты дисков, а затем использовать инструмент для их записи.)

Вы можете повторно использовать (адаптировать и повторно использовать) простой вариант программы из этого учебного пособия по Haskell для разделения вашей коллекции файлов.

К сожалению, в на distributeинструменте , который я уже упоминал здесь , в другом ответ , простота важнейшей задачи разделения не соответствует сложности и вздутием пользовательского интерфейса distribute(потому что она была написана , чтобы объединить несколько задач, хотя производятся поэтапно, но все же объединено не самым чистым способом, о котором я мог думать сейчас).

Чтобы помочь вам в некоторой степени использовать его код, вот выдержка из bash-кода distribute( строка 380 ), которая служит для выполнения этой «важной» задачи разделения коллекции файлов:

# Splitting:

function splitMirrorDir() {
  if [[ ! -d "$THIS_BASES_DIR/$BASE/$type" ]]; then
    echo $"No base fixed for $type" >&2
    exit 1
  fi

  # Getting the list of all suitable files:
  local -a allFiles
  let 'no = 0' ||:
  allFiles=()
  # no points to the next free position in allFiles
  # allFiles contains the constructed list
  for p in "$THIS_BASES_DIR/$BASE/$type"/*.rpm; do
      if [[ ! -e "$p" ]]; then
      # fail on non-existent files
      echo $"Package file doesn't exist: " "$p" >&2
      return 1 
      fi
      if [[ "$ONLY_REAL_FILES" == "yes" && ! -f "$p" ]]; then
      continue
      fi
      if [[ "$DIFF_TO_BASE" ]]; then
          older_copy="$DIFF_TO_BASE/$type/${p##*/}" # using shell param expansion instead of `basename' to speed up
          if [[ -h "$older_copy" || -a "$older_copy" ]]; then
          continue
      fi
      fi
      allFiles[$(( no++ ))]="$p"
  done
  readonly -a allFiles

  # Splitting the list of all files into future disks:
  # 
  local -a filesToEat allSizes
  let 'no = 0' ||:
  filesToEat=()
  allSizes=($(getSize "${allFiles[@]}"))
  readonly -a allSizes
  # allSizes contains the sizes corrsponding to allFiles
  # filesToEat hold the constructed list of files to put on the current disk
  # no points to the next free position in filesToEat
  # totalSize should hold the sum of the sizes 
  #  of the files already put into filesToEat;
  #  it is set and reset externally.
  for p in "${allFiles[@]}"; do 
      if (( totalsize + ${allSizes[$(( no ))]} > CDVOLUME )); then
      eatFiles "${filesToEat[@]}"
          filesToEat=()
          finishCD
      startTypedCD
    fi
      let "totalsize += ${allSizes[$(( no ))]}" ||:
      filesToEat[$(( no++ ))]="$p"
  done
  eatFiles "${filesToEat[@]}"
}

function eatFiles() {
    #{ oldIFS="$IFS"; IFS=$'\n'; echo "$FUNCNAME: args: " "$*" | head >&2;  IFS="$oldIFS"; }
    zeroDelimited "$@" | xargs -0 --no-run-if-empty \
    cp -s \
    --target-dir="$THIS_LAYOUTS_DIR/cd$(( cdN ))/$PREFIX/$type$DOT_SUFFIX"/ \
    --
}

function startTypedCD() {
#  set -x
  mkdir -p "$THIS_LAYOUTS_DIR/cd$(( cdN ))/$PREFIX/$type$DOT_SUFFIX"
  start_action $" %s with %s" "$(( cdN ))" "$type"
#  set +x
}

function finishCD() {

( подробнее после строки 454 )

Обратите внимание, что eatFilesфункция подготавливает макеты будущих дисков в виде деревьев, листья которых являются символическими ссылками на реальные файлы. Таким образом, он отвечает вашему требованию, чтобы вы могли редактировать макеты перед записью. mkisofsУтилита имеет возможность следовать символическим ссылкам, которая на самом деле используемая в коде моей mkisoфункции .

Представленный скрипт (который вы можете взять и переписать для своих нужд, конечно же!) Следует простейшей идее: суммировать размеры файлов (или, точнее, пакетов в случае distribute) в том порядке, в котором они были перечислены, дон не делать никаких перестановок.

«Руководство автостопом по Haskell» более серьезно относится к проблеме оптимизации и предлагает варианты программ, которые попытались бы разумно перестроить файлы, чтобы они лучше подходили для дисков (и требовали меньше дисков):

Уже достаточно предварительных экзаменов. давайте возьмем несколько компакт-дисков.

Как вы, возможно, уже поняли, наша проблема классическая. Это называется «проблема с рюкзаком» ( если вы еще не знаете, что это такое, запустите Google . Там более 100000 ссылок).

давайте начнем с жадного решения ...

(подробнее читайте в Главе 3 и далее.)

Другие умные инструменты

Мне также сказали, что Debian использует инструмент для создания своих дистрибутивных компакт-дисков, который умнее, чем мои distributeколлекции пакетов: его результаты более хороши, потому что он заботится о зависимостях между пакетами и пытается создать коллекцию пакетов, которая попадает на первый диск закрыт под зависимостями, то есть ни один пакет с 1-го диска не должен требовать пакет с другого диска (или, по крайней мере, я бы сказал, количество таких зависимостей должно быть минимизировано).

imz - Иван Захарящев
источник
1

Backup2l может сделать много этой работы. Даже если вы не используете пакет напрямую, вы можете получить некоторые идеи сценария из него.

Рэнди Коулман
источник
0

rarАрхиватор может быть поручен автоматически разбивает архив создается на куски такого размера , определенного с -vsizeфлагом.

Архивирование этого дерева каталогов с именами foo, скажем, 500 мегабайт за штуку, которые вы бы указали
rar a backup.rar -v500m foo/

Shadur
источник
2
Чем почему рар? tar (+ bz2) + split - более нативный подход для * nix.
RVS
«Деревья размером с прикус» не совсем звучат rar, если только вы снова не распакуете каждую «деталь» в свой собственный каталог, что, конечно, не сработает, поскольку детали не спроектированы таким образом и не разбиты по границам файлов.
MattBianco
1
Если говорить об инструментах, которые дают tar+ split-подобные результаты, то есть и дар ; вот примечание о его соответствующей функции: «(SLICES) оно было разработано, чтобы иметь возможность разделить архив на несколько сменных носителей, независимо от их количества и размера». По сравнению с tar+ split, я предполагаю, что он позволяет несколько более простых способов доступа к архивным файлам. (Кстати, у него есть также функция, напоминающая distribute: «DIFFERENTIAL BACKUP» и «DIRECTORY TREE SNAPSHOT», но может не понравиться, что в результате получается специальный формат, а не ISO с деревом dir.)
imz - Иван Захарящев