Розщеплення великого дерева каталогів на шматки заданого розміру?


11

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

Це не фантазійний сценарій, але, схоже, це вже було зроблено. Пропозиції?

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


Чи розглядали ви як письменник з блюраї?
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"

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


Я вніс кілька змін у ваш сценарій, щоб впоратися зі спеціальними символами у назвах файлів (пробіл, початкові тире та крапки \[?*). Пропоноване читання: не розбирайте вихід ls , $ VAR проти $ {VAR} і не цитуйте чи не цитуйте . Зауважте, що я не перевірив отриманий скрипт. Якщо ви не розумієте жодних моїх змін, сміливо запитайте.
Жил 'ТАК - перестань бути злим'

@Gilles: Я багато читав з 2008 року ;-) Зміни, щоб зробити сценарій більш загальним, хороші. (Я не люблю введення, на [відміну від цього test) ...
MattBianco

Більшість цих змінних слід зменшити. За умовою ми використовуємо великі величини середовища (PAGER, EDITOR, SHELL, ...) та внутрішні змінні оболонки. Усі інші назви змінних повинні містити принаймні одну малу літеру. Ця конвенція дозволяє уникнути випадкових переваг екологічних та внутрішніх змінних.
Кріс Даун

2

Я колись написав сценарій для вирішення подібної проблеми - я назвав його "розподілити" (ви можете прочитати основний код сценарію або файл із повідомленням довідки , або завантажити його як пакет ); з його опису :

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

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

Періодичні оновлення первісно розподіленої колекції можуть бути видані за допомогою `distribute '.

Він виконує весь процес у декілька етапів: на одному етапі він створює диски furure "макети", використовуючи посилання на оригінальні файли - таким чином, ви можете втрутитися та змінити майбутні дерева дисків.

Деталі про його використання можна прочитати у довідковому повідомленні, надрукованому сценарієм (або заглянувши у вихідний код).

Він був написаний з більш складним випадком використання на увазі (видача оновлень як "diff" - набір доданих нових файлів - до первісно записаної колекції файлів), тому він включає один додатковий початковий етап, а саме "виправлення "поточний стан колекції файлів (для простоти це робиться шляхом реплікації оригінальної колекції файлів за допомогою символьних посилань, у спеціальному робочому місці для збереження станів колекції; потім, деякий час у майбутньому, це зможе створити різницю між майбутнім поточним станом колекції файлів і цим збереженим станом). Отже, хоча ця функція може не знадобитися, ви не можете пропустити цей початковий етап, AFAIR.

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

Інформація, що стосується APT, не є обов'язковою, тому не звертайте уваги, що вона може готувати колекції пакетів, які будуть використовуватися APT, якщо цього вам не потрібно.

Якщо вас зацікавить, звичайно, сміливо переписуйте його під свої потреби або пропонуйте вдосконалення.

(Зверніть увагу, що пакет включає додаткові корисні патчі, які не застосовуються у представленому списку кодів у Git repo, пов’язаному вище!)


Я представив - серед інших речей - уривок з коду 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" серйозно ставиться до проблеми оптимізації та пропонує варіанти програм, які б спробувати перевпорядкувати файли на розумному рівні, щоб вони краще вміщувалися на дисках (та вимагали менше дисків):

Досить попередніх ліній. підемо спакувати кілька компакт-дисків.

Як ви вже могли визнати, наша проблема є класичною. Це називається "проблема з рубанням" ( гугл вгору , якщо ви вже не знаєте, що це таке. Є більше 100000 посилань).

почнемо з жадного рішення ...

(детальніше читайте у розділі 3 та далі.)

Інші розумні інструменти

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


1

backup2l може зробити багато цієї роботи. Навіть якщо ви не використовуєте пакет безпосередньо, ви можете отримати від нього кілька ідей сценарію.


0

rarАрхіватор може бути доручений автоматично розбиває архів створюється на шматки такого розміру , визначеного з -vsizeпрапором.

Заархівуючи це дерево каталогів, назване fooв шматки, скажімо, 500 мегабайт за штуку, яку ви вказали
rar a backup.rar -v500m foo/


2
Чому чому рідкість? tar (+ bz2) + split - більш рідний підхід для * nix.
rvs

"дерева розміру" не дуже схожі rar, якщо ви знову не розпакуйте кожну "частину" у свій каталог, що, звичайно, не буде працювати, оскільки частини не створені таким чином і не розбиваються на межі файлів.
MattBianco

1
Якщо говорити про інструменти, які дають tar+ split-подібні результати, то також є дар ; ось примітка про його відповідну особливість: "(SLICES) він був розроблений таким чином, щоб можна було розділити архів на кілька знімних носіїв незалежно від їх кількості та незалежно від їх розміру". У порівнянні з tar+ split, я припускаю, це дозволяє простіше отримати доступ до архівованих файлів. (BTW, він також має особливість, що нагадує distribute: "
РІЗНОВА РЕЗЕРВАЦІЯ" та "РЕГІСТРАЦІЯ ДИРЕКЦІЙНОГО ДРУГА
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.