Aufteilen eines großen Verzeichnisbaums in Blöcke mit der angegebenen Größe?

11

Ich habe einen Verzeichnisbaum, den ich auf optischen Datenträgern sichern möchte. Leider überschreitet es die Größe einer Festplatte (etwa 60 GB). Ich suche nach einem Skript, das diesen Baum in entsprechend große Teile mit harten Links oder so weiter aufteilt (wobei das Original unberührt bleibt). Ich könnte diese mundgerechten Bäume dann in den Sicherungsprozess einspeisen (PAR2-Redundanz hinzufügen usw.).

Es ist kein ausgefallenes Skript, aber es scheint, als wäre es bereits fertig. Vorschläge?

(Das Überspannen und Schreiben in einem Schritt ist ein No-Go, da ich mehr tun möchte, bevor die Dateien gebrannt werden.)

Reid
quelle
Haben Sie darüber nachgedacht, einen Bluray-Autor zu bekommen?
BSD
2
DVD-Medien sind unzuverlässig ... Ich würde ein externes Laufwerk, ein Online-Backup wie Carbonite empfehlen oder beim Brennen von Medien einen gewissen par2Schutz verwenden.
Aaron D. Marasco

Antworten:

7

Es gibt eine Anwendung, die dafür entwickelt wurde: dirsplit

Es lebt normalerweise in cdrkitoder dirsplitPaketen.

Es kann gebrauchsfertige Ordner mit Links erstellen, um DVDs einfach mit K3b oder einer anderen GUI-Software zu erstellen

Hubert Kario
quelle
Das hat sehr gut funktioniert. In Ubuntu habe ich es im genisoimagePaket gefunden.
Nograpes
2

Ich habe einmal ein hässliches Skript für einen ähnlichen Zweck erstellt. Es ist nur ein Kludge, aber als ich es schrieb, war mir die Ausführungszeit oder die Schönheit egal. Ich bin mir sicher, dass es mehr "produktive" Versionen desselben Konzepts gibt, aber wenn Sie Ideen oder etwas zum Hacken haben möchten, gehen Sie wie folgt vor (haben Sie es 2008 getan, verwenden Sie es also auf eigenes Risiko!): - )

#!/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"

Ich glaube, ich hatte das Ergebnis über Samba an einen Windows-Host weitergegeben, der Discs davon gebrannt hat. Wenn Sie die oben genannten unverändert verwenden, möchten Sie möglicherweise einen mkisofsanderen Archivierer verwenden, der Symlinks auflöst.

MattBianco
quelle
Ich habe einige Änderungen an Ihrem Skript vorgenommen, um mit Sonderzeichen in Dateinamen (Leerzeichen, anfängliche Striche und Punkte \[?*) fertig zu werden . Empfohlene Lektüre: Analysieren Sie nicht die Ausgabe von ls , $ VAR vs $ {VAR} und zitieren Sie oder zitieren Sie nicht . Beachten Sie, dass ich das resultierende Skript nicht getestet habe. Wenn Sie eine meiner Änderungen nicht verstehen, können Sie sie gerne fragen.
Gilles 'SO - hör auf böse zu sein'
@ Gilles: Ich habe seit 2008 viel gelesen ;-) Änderungen, um das Skript allgemeiner zu gestalten, sind gut. (Ich mag die Einführung von [im Gegensatz zu nicht test) ...
MattBianco
Sie sollten die meisten dieser Variablen in Kleinbuchstaben schreiben. Konventionell setzen wir Umgebungsvariablen (PAGER, EDITOR, SHELL, ...) und interne Shell-Variablen in Großbuchstaben. Alle anderen Variablennamen sollten mindestens einen Kleinbuchstaben enthalten. Diese Konvention vermeidet das versehentliche Überschreiben von Umgebungsvariablen und internen Variablen.
Chris Down
2

Ich habe einmal ein Skript geschrieben, um ein ähnliches Problem zu lösen - ich habe es "verteilen" genannt (Sie können den Hauptcode des Skripts oder der Datei mit der Hilfemeldung lesen oder als Paket herunterladen ). aus seiner Beschreibung :

verteilen - Verteilen Sie eine Sammlung von Paketen auf mehreren CDs (besonders gut für die zukünftige Verwendung mit APT geeignet).

Beschreibung: Das Programm "Distribute" erleichtert die Ausführung der Aufgaben im Zusammenhang mit der Erstellung eines CD-Sets für die Verteilung einer Sammlung von Paketen. Die Aufgaben umfassen: Auslegen des CD-Dateisystems (Aufteilen der großen Anzahl von Paketen auf mehrere Discs usw.), Vorbereiten der Sammlung für die Verwendung durch APT (Indizieren), Erstellen von ISO-Images und Aufzeichnen der Discs.

Regelmäßige Aktualisierungen der ursprünglich verteilten Sammlung können mit Hilfe von "Verteilen" ausgegeben werden.

Der gesamte Vorgang wird in mehreren Schritten ausgeführt: In einer Phase werden die "Layouts" der Furure-Festplatte mithilfe von Symlinks zu den Originaldateien erstellt, sodass Sie eingreifen und die zukünftigen Festplattenbäume ändern können.

Die Details zu seiner Verwendung können in der vom Skript gedruckten Hilfemeldung (oder im Quellcode) nachgelesen werden.

Es wurde für einen schwierigeren Anwendungsfall geschrieben (Ausgabe von Updates als "Diff" - die Menge der hinzugefügten neuen Dateien - für die ursprünglich aufgezeichnete Dateisammlung), sodass es eine zusätzliche Anfangsphase enthält, nämlich "Fixing" "Der aktuelle Status der Dateisammlung (der Einfachheit halber wird dazu die ursprüngliche Dateisammlung mithilfe von Symlinks repliziert, und zwar an einem speziellen Arbeitsplatz, um die Status der Sammlung zu speichern. Dann, irgendwann in der Zukunft." wird in der Lage sein, einen Unterschied zwischen einem zukünftigen aktuellen Status der Dateisammlung und diesem gespeicherten Status zu erstellen). Obwohl Sie diese Funktion möglicherweise nicht benötigen, können Sie diese Anfangsphase, AFAIR, nicht überspringen.

Außerdem bin ich mir jetzt nicht sicher (ich habe es vor einigen Jahren geschrieben), ob es komplexe Bäume gut behandelt oder ob es nur einfache (einstufige) Dateiverzeichnisse aufteilen soll. (Bitte schauen Sie in die Hilfemeldung oder den Quellcode, um sicherzugehen. Ich werde dies auch etwas später nachschlagen, wenn ich etwas Zeit habe.)

Das APT-bezogene Material ist optional. Achten Sie also nicht darauf, dass es Paketsammlungen für die Verwendung durch APT vorbereiten kann, wenn Sie dies nicht benötigen.

Wenn Sie interessiert sind, können Sie es natürlich nach Ihren Wünschen umschreiben oder Verbesserungen vorschlagen.

(Bitte beachten Sie, dass das Paket zusätzliche nützliche Patches enthält, die nicht in der oben aufgeführten Codeliste des oben verlinkten Git-Repos enthalten sind!)

imz - Ivan Zakharyaschev
quelle
Ich habe - unter anderem - den Code-Auszug vorgestellt distribute, der die hier gestellte wesentliche Aufgabe löst.
imz - Ivan Zakharyaschev
2

Wir sollten nicht vergessen, dass das Wesentliche der Aufgabe in der Tat recht einfach ist; wie in einem Tutorial über Haskell (das sich um das Durcharbeiten der Lösung für diese Aufgabe dreht, schrittweise verfeinert)

Lassen Sie uns nun einen Moment darüber nachdenken, wie unser Programm funktionieren wird, und es im Pseudocode ausdrücken:

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

Klingt vernünftig? Ich dachte auch.

Lassen Sie uns unser Leben ein wenig vereinfachen und davon ausgehen, dass wir die Verzeichnisgrößen irgendwo außerhalb unseres Programms berechnen (zum Beispiel mit " du -sb *") und diese Informationen von stdin lesen.

(vom Per Anhalter durch Haskell, Kapitel 1 )

(Außerdem möchten Sie in Ihrer Frage in der Lage sein, die resultierenden Festplattenlayouts zu optimieren (zu bearbeiten) und sie dann mit einem Tool zu brennen.)

Sie können eine einfache Variante des Programms aus diesem Haskell-Tutorial zum Aufteilen Ihrer Dateisammlung wiederverwenden (anpassen und wiederverwenden).

Leider wird in dem distributeTool, das ich hier in einer anderen Antwort erwähnt habe , die Einfachheit der wesentlichen Aufteilungsaufgabe nicht durch die Komplexität und Aufblähung der Benutzeroberfläche von erreicht distribute(da es geschrieben wurde, um mehrere Aufgaben zu kombinieren, obwohl es schrittweise ausgeführt wird). aber immer noch nicht so sauber kombiniert, wie ich es mir jetzt vorstellen kann).

Um Ihnen zu helfen, den Code besser zu nutzen, finden Sie hier einen Auszug aus dem Bash-Code von distribute(in Zeile 380 ), der dazu dient, diese "wesentliche" Aufgabe des Aufteilens einer Sammlung von Dateien auszuführen :

# 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() {

( Lesen Sie mehr nach Zeile 454 )

Beachten Sie, dass die eatFilesFunktion die Layouts der zukünftigen Datenträger als Bäume vorbereitet, in denen die Blätter Symlinks zu den realen Dateien darstellen. Es entspricht also Ihrer Anforderung, dass Sie die Layouts vor dem Brennen bearbeiten können müssen. Das mkisofsDienstprogramm hat die Option, Symlinks zu folgen, die tatsächlich im Code meiner mkisoFunktion verwendet werden .

Das vorgestellte Skript (das Sie natürlich nehmen und nach Ihren Wünschen umschreiben können!) Folgt der einfachsten Idee: Die Größe der Dateien (oder genauer gesagt der Pakete im Fall von distribute) nur in der angegebenen Reihenfolge zu summieren , don Keine Umlagerungen vornehmen.

Der "Per Anhalter durch Haskell" nimmt das Optimierungsproblem ernst und schlägt Programmvarianten vor, die versuchen würden, die Dateien intelligent neu anzuordnen, damit sie besser auf Datenträger passen (und weniger Datenträger benötigen):

Genug Vorbereitungen schon. Lass uns ein paar CDs packen.

Wie Sie vielleicht bereits erkannt haben, ist unser Problem ein klassisches. Es wird als "Rucksackproblem" bezeichnet ( googeln Sie es , wenn Sie noch nicht wissen, was es ist. Es gibt mehr als 100000 Links).

Beginnen wir mit der gierigen Lösung ...

(Lesen Sie mehr in Kapitel 3 und weiter.)

Andere intelligente Werkzeuge

Mir wurde auch gesagt, dass Debian ein Tool verwendet, um seine Distributions-CDs zu distributeerstellen , das intelligenter ist als meine schriftlichen Paketsammlungen: Die Ergebnisse sind besser, weil es sich um Abhängigkeiten zwischen Paketen kümmert und versuchen würde, die Sammlung von Paketen zu erstellen, die sich weiterentwickeln Die erste Festplatte, die unter Abhängigkeiten geschlossen wurde, dh, kein Paket von der ersten Festplatte sollte ein Paket von einer anderen Festplatte erfordern (oder zumindest sollte die Anzahl solcher Abhängigkeiten minimiert werden).

imz - Ivan Zakharyaschev
quelle
1

backup2l kann einen Großteil dieser Arbeit erledigen. Selbst wenn Sie das Paket nicht direkt verwenden, erhalten Sie möglicherweise einige Skriptideen.

Randy Coulman
quelle
0

Der rarArchivierer kann angewiesen werden, das von ihm erstellte Archiv automatisch in Blöcke einer bestimmten Größe mit dem -vsizeFlag aufzuteilen .

Archivieren Sie diesen Verzeichnisbaum fooin Blöcken von beispielsweise 500 Megabyte pro Stück, die Sie angeben würden
rar a backup.rar -v500m foo/

Shadur
quelle
2
Als warum rar? tar (+ bz2) + split ist ein nativerer Ansatz für * nix.
RVS
"Bissgroße Bäume" klingen nicht ganz so rar, es sei denn, Sie entpacken jedes "Teil" erneut in ein eigenes Verzeichnis, was natürlich nicht funktioniert, da die Teile nicht so gestaltet und nicht an Dateigrenzen aufgeteilt sind.
MattBianco
1
Wenn es um Tools geht, die tar+ split-ähnliche Ergebnisse liefern, dann gibt es auch dar ; Hier ist der Hinweis zu seiner relevanten Funktion: "(SLICES) Es wurde entwickelt, um ein Archiv auf mehrere Wechselmedien aufteilen zu können, unabhängig von ihrer Anzahl und Größe." Im Vergleich zu tar+ splitbietet es vermutlich einige einfachere Möglichkeiten, auf die archivierten Dateien zuzugreifen. (Übrigens hat es auch eine ähnliche Funktion distribute: "DIFFERENTIAL BACKUP" & "DIRECTORY TREE SNAPSHOT", aber es mag nicht gefallen, dass das Ergebnis ein spezielles Format ist, keine ISO mit einem
Verzeichnisbaum