¿Dividir un gran árbol de directorios en fragmentos de tamaño especificado?

11

Tengo un árbol de directorios que me gustaría hacer una copia de seguridad en los discos ópticos. Desafortunadamente, excede el tamaño de cualquier disco (es de aproximadamente 60 GB). Estoy buscando un script que divida este árbol en fragmentos de tamaño apropiado con enlaces duros o cualquier otra cosa (dejando el original intacto). Luego podría alimentar estos árboles de tamaño de bocado en el proceso de copia de seguridad (agregar redundancia PAR2, etc.).

No es un script sofisticado, pero parece que ya se ha hecho. Sugerencias?

(Abordar y escribir en un solo paso es imposible porque quiero hacer más cosas antes de que se quemen los archivos).

Reid
fuente
¿Has considerado conseguir un escritor bluray?
bsd
2
Los medios de DVD no son confiables ... Recomiendo una unidad externa, una copia de seguridad en línea como Carbonite, o si graba medios, use alguna par2protección.
Aaron D. Marasco

Respuestas:

7

Existe una aplicación diseñada para esto: dirsplit

Suele vivir en cdrkito dirsplitpaquetes.

Puede crear carpetas listas para usar con enlaces para crear fácilmente DVD con K3b u otro software GUI

Hubert Kario
fuente
Esto funcionó muy bien. En Ubuntu lo encontré en el genisoimagepaquete.
nograpes
2

Una vez hice un guión feo para un propósito similar. Es solo un error, pero cuando lo escribí no me importaba el tiempo de ejecución o la belleza. Estoy seguro de que hay más versiones "productificadas" del mismo concepto, pero si desea obtener algunas ideas o algo para comenzar a hackear, aquí va (¡lo hizo en 2008, así que úselo bajo su propio riesgo!): )

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

Creo que compartí el resultado a través de samba con un host de Windows que grabó discos de él. Si usa lo anterior sin modificaciones, es posible que desee usar mkisofsu otro archivador que resuelva enlaces simbólicos.

MattBianco
fuente
He realizado algunos cambios en su script para hacer frente a caracteres especiales en los nombres de los archivos (espacios en blanco, guiones iniciales y puntos \[?*). Lectura sugerida: no analice la salida de ls , $ VAR vs $ {VAR} y cite o no cite . Tenga en cuenta que no he probado el script resultante. Si no entiende uno de mis cambios, no dude en preguntar.
Gilles 'SO- deja de ser malvado'
@Gilles: He leído mucho desde 2008 ;-) Los cambios para que el script sea más genérico son buenos. (Sin embargo, no me gusta la introducción de [en lugar de test) ...
MattBianco
Debe minúsculas la mayoría de esas variables. Por convención, capitalizamos las variables de entorno (PAGER, EDITOR, SHELL, ...) y las variables internas del shell. Todos los demás nombres de variables deben contener al menos una letra minúscula. Esta convención evita anular accidentalmente variables ambientales e internas.
Chris Down
2

Una vez escribí un script para resolver un problema similar: lo llamé "distribuir" (puede leer el código principal del script o el archivo con el mensaje de ayuda , o descargarlo como un paquete ); de su descripción :

distribuir : distribuir una colección de paquetes en varios CD (especialmente bueno para uso futuro con APT)

Descripción: el programa 'distribuir' facilita las tareas relacionadas con la creación de un conjunto de CD para la distribución de una colección de paquetes. Las tareas incluyen: diseñar el sistema de archivos de CD (dividir la gran cantidad de paquetes en varios discos, etc.), preparar la colección para su uso por APT (indexación), crear imágenes ISO y grabar los discos.

Las actualizaciones periódicas de la colección inicialmente distribuida se pueden emitir con la ayuda de 'distribuir'.

Realiza todo el proceso en varias etapas: en una etapa, crea los "diseños" del disco furure mediante el uso de enlaces simbólicos a los archivos originales, para que pueda intervenir y cambiar los futuros árboles de discos.

Los detalles sobre su uso se pueden leer en el mensaje de ayuda impreso por el script (o mirando el código fuente).

Fue escrito con un caso de uso más complicado en mente (emitir actualizaciones como "diff" - el conjunto de archivos nuevos agregados - a la colección de archivos grabada originalmente), por lo que incluye una etapa inicial adicional, a saber, "arreglar "el estado actual de la colección de archivos (por simplicidad, lo hace replicando la colección original de archivos mediante enlaces simbólicos, en un lugar de trabajo especial para guardar los estados de la colección; luego, en algún momento en el futuro, podrá crear una diferencia entre un estado actual futuro de la colección de archivos y este estado guardado). Entonces, aunque es posible que no necesite esta función, no puede saltarse esta etapa inicial, AFAIR.

Además, ahora no estoy seguro (lo escribí hace unos años) si trata bien los árboles complejos o si se supone que divide solo directorios de archivos simples (de un nivel). (Por favor, mire el mensaje de ayuda o el código fuente para asegurarse; buscaré esto también, un poco más tarde, cuando tenga algo de tiempo).

Las cosas relacionadas con APT son opcionales, así que no preste atención porque puede preparar colecciones de paquetes para que APT las use si no las necesita.

Si le interesa, por supuesto, siéntase libre de reescribirlo según sus necesidades o sugerir mejoras.

(¡Tenga en cuenta que el paquete incluye parches útiles adicionales no aplicados en la lista de códigos presentada en el repositorio de Git vinculado anteriormente!)

imz - Ivan Zakharyaschev
fuente
He presentado, entre otras cosas, el extracto del código distributeque resuelve la tarea esencial que se pregunta aquí.
imz - Ivan Zakharyaschev
2

No debemos olvidar que la esencia de la tarea es bastante simple; como se puso en un tutorial sobre Haskell (que está escrito en torno a la solución de esta tarea, refinada gradualmente)

Ahora pensemos por un momento acerca de cómo funcionará nuestro programa y expresémoslo en pseudocódigo:

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

¿Suena razonable? Ya me lo imaginaba.

Simplifiquemos un poco nuestra vida y supongamos por ahora que calcularemos los tamaños de directorio en algún lugar fuera de nuestro programa (por ejemplo, con " du -sb *") y leeremos esta información de stdin.

(de la guía Hitchhikers de Haskell, Capítulo 1 )

(Además, en su pregunta, le gustaría poder ajustar (editar) los diseños de disco resultantes y luego usar una herramienta para grabarlos).

Puede reutilizar (adaptar y reutilizar) una variante simple del programa de ese tutorial de Haskell para dividir su colección de archivos.

Desafortunadamente, en la distributeherramienta que he mencionado aquí en otra respuesta , la simplicidad de la tarea de división esencial no se corresponde con la complejidad y la hinchazón de la interfaz de usuario distribute(porque fue escrita para combinar varias tareas; aunque se realizó en etapas, pero aun así combinado no de la manera más limpia que se me ocurra ahora).

Para ayudarlo a utilizar su código, aquí hay un extracto del código bash de distribute(en la línea 380 ) que sirve para realizar esta tarea "esencial" de dividir una colección de archivos:

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

( lea más después de la línea 454 )

Tenga en cuenta que la eatFilesfunción prepara los diseños de los futuros discos como árboles donde las hojas son enlaces simbólicos a los archivos reales. Por lo tanto, cumple con su requisito de poder editar los diseños antes de grabar. La mkisofsutilidad tiene una opción para seguir enlaces simbólicos, que de hecho se emplea en el código de mi mkisofunción .

El guión presentado (¡que puede tomar y reescribir según sus necesidades, por supuesto!) Sigue la idea más simple: para sumar los tamaños de los archivos (o, más precisamente, los paquetes en el caso de distribute) solo en el orden en que se enumeraron, don No haga ningún reordenamiento.

La "Guía de autoestopistas de Haskell" toma el problema de optimización más en serio y sugiere variantes de programa que intentarían reorganizar los archivos de manera inteligente, para que se ajusten mejor a los discos (y requieran menos discos):

Ya hay suficientes preliminares. vamos a empacar algunos CD.

Como ya habrás reconocido, nuestro problema es clásico. Se llama un "problema de mochila" ( búscalo en Google , si aún no sabes qué es. Hay más de 100000 enlaces).

empecemos por la solución codiciosa ...

(lea más en el Capítulo 3 y más).

Otras herramientas inteligentes

También me han dicho que Debian usa una herramienta para hacer sus CD de distribución que es más inteligente que mis distributecolecciones de paquetes wrt: sus resultados son mejores porque se preocupa por las dependencias entre paquetes y trataría de hacer la colección de paquetes que sigue el primer disco cerrado bajo dependencias, es decir, ningún paquete del primer disco debería requerir un paquete de otro disco (o al menos, diría, el número de tales dependencias debería minimizarse).

imz - Ivan Zakharyaschev
fuente
1

backup2l puede hacer mucho de este trabajo. Incluso si no usa el paquete directamente, puede obtener algunas ideas de script.

Randy Coulman
fuente
0

Se rarpuede indicar al archivador que divida automáticamente el archivo que crea en trozos de un tamaño específico con la -vsizebandera.

Archivando ese árbol de directorios nombrado fooen trozos de, digamos, 500 megabytes cada uno que especificaría
rar a backup.rar -v500m foo/

Shadur
fuente
2
¿Por qué rar? tar (+ bz2) + split es un enfoque más nativo para * nix.
rvs
Los "árboles del tamaño de un bocado" no suenan del todo rar, a menos que desempaquete cada "parte" nuevamente en su propio directorio, que por supuesto no funcionará, ya que las partes no están diseñadas de esa manera y no se dividen en los límites de los archivos.
MattBianco
1
Si hablamos de herramientas que dan resultados similares a tar+ split, entonces también hay dar ; Aquí está la nota sobre su característica relevante: "(SLICES) fue diseñado para poder dividir un archivo en varios medios extraíbles, cualquiera sea su número y su tamaño". En comparación con tar+ split, supongo, permite algunas formas más fáciles de acceder a los archivos archivados. (Por cierto, también tiene una característica similar a distribute: "RESPALDO DIFERENCIAL" y "INSTANTÁNEO DE ÁRBOL DE DIRECTORIO", pero a uno no le gusta que el resultado sea un formato especial, no un ISO con un árbol de directorios.)
imz - Ivan Zakharyaschev