Dividere l'albero delle directory di grandi dimensioni in blocchi di dimensioni specificate?


11

Ho un albero di directory di cui vorrei eseguire il backup su dischi ottici. Sfortunatamente, supera le dimensioni di qualsiasi disco (è di circa 60 GB). Sto cercando una sceneggiatura che divida questo albero in blocchi di dimensioni adeguate con collegamenti rigidi o quant'altro (lasciando intatto l'originale). Potrei quindi inserire questi alberi di dimensioni ridotte nel processo di backup (aggiungere ridondanza PAR2, ecc.).

Non è una sceneggiatura elegante, ma sembra che potrebbe essere già stato fatto. Suggerimenti?

(Eseguire lo spanning e la scrittura in un solo passaggio è un gioco da ragazzi perché voglio fare più cose prima che i file vengano masterizzati.)


Hai mai pensato di ottenere uno scrittore sfocato?
bsd

2
I supporti DVD non sono affidabili ... Consiglierei un'unità esterna, un backup online come Carbonite o, se si masterizzano supporti, utilizzare una par2protezione.
Aaron D. Marasco,

Risposte:


7

Esiste un'applicazione progettata per questo: dirsplit

Di solito vive cdrkito in dirsplitpacchetti.

Può creare cartelle pronte all'uso con collegamenti per creare facilmente DVD con K3b o altri software GUI


Questo ha funzionato davvero bene. In Ubuntu l'ho trovato nel genisoimagepacchetto.
nograpes,


2

Una volta ho realizzato una brutta sceneggiatura per uno scopo simile. È solo un kludge, ma quando l'ho scritto non mi importava del tempo di esecuzione o della bellezza. Sono sicuro che ci sono più versioni "prodotte" dello stesso concetto in giro, ma se desideri avere alcune idee o qualcosa su cui iniziare l'hacking, ecco qui (fatto nel 2008, quindi usalo a tuo rischio e pericolo!): - )

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

Penso di aver condiviso il risultato tramite samba con un host Windows che ha masterizzato i dischi da esso. Se si utilizza inalterato quanto sopra, si potrebbe desiderare di utilizzare mkisofso un altro archiviatore che risolve i collegamenti simbolici.


Ho apportato alcune modifiche al tuo script per far fronte a caratteri speciali nei nomi dei file (spazi bianchi, trattini e punti iniziali \[?*). Lettura consigliata: non analizzare l'output di ls , $ VAR vs $ {VAR} e per citare o non citare . Nota che non ho testato lo script risultante. Se non capisci una delle mie modifiche, non esitare a chiedere.
Gilles 'SO-smetti di essere malvagio' il

@Gilles: ho fatto molte letture dal 2008 ;-) Le modifiche per rendere la sceneggiatura più generica sono buone. (Non mi piace l'introduzione di [al contrario test, però) ...
MattBianco,

Dovresti minuscole la maggior parte di quelle variabili. Per convenzione, capitalizziamo le variabili di ambiente (PAGER, EDITOR, SHELL, ...) e le variabili di shell interne. Tutti gli altri nomi di variabili devono contenere almeno una lettera minuscola. Questa convenzione evita di ignorare accidentalmente le variabili ambientali e interne.
Chris Down,

2

Una volta ho scritto uno script per risolvere un problema simile - l'ho chiamato "distribuisci" (puoi leggere il codice principale dello script o il file con il messaggio di aiuto o scaricarlo come pacchetto ); dalla sua descrizione :

distribuire - Distribuire una raccolta di pacchetti su più CD (particolarmente utile per un utilizzo futuro con APT)

Descrizione: il programma `distribut 'semplifica l'esecuzione delle attività relative alla creazione di un set di CD per la distribuzione di una raccolta di pacchetti. I compiti includono: strutturare il filesystem dei CD (suddividere la grande quantità di pacchetti in diversi dischi, ecc.), Preparare la raccolta per l'uso da parte di APT (indicizzazione), creare immagini ISO e registrare i dischi.

Aggiornamenti periodici alla raccolta inizialmente distribuita possono essere emessi con l'aiuto di "distribuire".

Esegue l'intero processo in più fasi: in una fase crea i "layout" del disco furie utilizzando i collegamenti simbolici ai file originali, in modo da poter intervenire e modificare i futuri alberi del disco.

I dettagli sul suo utilizzo possono essere letti nel messaggio di aiuto stampato dallo script (o cercando nel codice sorgente).

È stato scritto con un caso d'uso più complicato in mente (emissione di aggiornamenti come "diff" - l'insieme di nuovi file aggiunti - alla raccolta di file registrata originariamente), quindi include una fase iniziale aggiuntiva, ovvero "fissaggio "lo stato corrente della raccolta di file (per semplicità, lo fa replicando la raccolta originale di file per mezzo di collegamenti simbolici, in un posto di lavoro speciale per salvare gli stati della raccolta; quindi, qualche tempo in futuro, sarà in grado di creare una differenza tra un futuro stato attuale della raccolta di file e questo stato salvato). Quindi, anche se potresti non aver bisogno di questa funzione, non puoi saltare questa fase iniziale, AFAIR.

Inoltre, non sono sicuro ora (l'ho scritto alcuni anni fa) se tratta bene alberi complessi, o se si suppone che divida solo directory di file semplici (un livello). (Per favore, controlla il messaggio di aiuto o il codice sorgente per essere sicuro; lo cercherò anche un po 'più tardi, quando avrò del tempo.)

Le cose relative ad APT sono opzionali, quindi non prestare attenzione al fatto che può preparare raccolte di pacchetti da usare da APT se non ne hai bisogno.

Se ti interessa, naturalmente, sentiti libero di riscriverlo secondo le tue esigenze o suggerire miglioramenti.

(Prestare attenzione al fatto che il pacchetto include ulteriori utili patch non applicate nell'elenco dei codici presentati nel repository Git collegato sopra!)


Ho presentato - tra le altre cose - il codice estratto da distributequello che risolve il compito essenziale richiesto qui.
imz - Ivan Zakharyaschev

2

Non dovremmo dimenticare che l'essenza del compito è davvero abbastanza semplice; come messo in un tutorial su Haskell (che è scritto attorno all'elaborazione della soluzione per questa attività, perfezionata in modo incrementale)

Ora pensiamo per un momento a come funzionerà il nostro programma ed esprimiamolo in pseudocodice:

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

Sembra ragionevole? Così ho pensato.

Semplifichiamo un po 'la nostra vita e supponiamo per ora che calcoleremo le dimensioni delle directory da qualche parte al di fuori del nostro programma (ad esempio, con " du -sb *") e leggeremo queste informazioni da stdin.

(dalla guida degli autostoppisti a Haskell, capitolo 1 )

(Inoltre, nella tua domanda, vorresti essere in grado di modificare (modificare) i layout del disco risultanti e quindi utilizzare uno strumento per masterizzarli.)

Puoi riutilizzare (adattare e riutilizzare) una semplice variante del programma da quel tutorial Haskell per dividere la tua raccolta di file.

Purtroppo, nel l' distributeattrezzo che ho accennato qui in un'altra risposta , la semplicità del compito essenziale la divisione non è compensata dalla complessità e gonfiore dell'interfaccia utente di distribute(perché è stato scritto per combinare diversi compiti, anche se eseguita in più fasi, ma ancora combinato non nel modo più pulito a cui potrei pensare ora).

Per aiutarti a fare un po 'di uso del suo codice, ecco un estratto dal codice bash distribute(alla riga 380 ) che serve a fare questo compito "essenziale" di dividere una raccolta di file:

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

( leggi di più dopo la riga 454 )

Si noti che la eatFilesfunzione prepara i layout dei dischi futuri come alberi in cui le foglie sono collegamenti simbolici ai file reali. Quindi, soddisfa i tuoi requisiti che dovresti essere in grado di modificare i layout prima della masterizzazione. L' mkisofsutilità ha un'opzione per seguire i collegamenti simbolici, che è effettivamente impiegato nel codice della mia mkisofunzione .

Lo script presentato (che puoi prendere e riscrivere in base alle tue esigenze, ovviamente!) Segue l'idea più semplice: sommare le dimensioni dei file (o, più precisamente, i pacchetti nel caso di distribute) proprio nell'ordine in cui sono stati elencati, don non fare alcun riarrangiamento.

La "Guida degli autostoppisti a Haskell" prende più seriamente il problema dell'ottimizzazione e suggerisce varianti di programma che tenterebbero di riorganizzare i file in modo intelligente, in modo che si adattino meglio ai dischi (e richiedano meno dischi):

Già abbastanza preliminari. andiamo a fare un po 'di cd.

Come forse avrai già riconosciuto, il nostro problema è classico. Si chiama "problema dello zaino" ( cercalo su Google , se non sai già di cosa si tratta. Ci sono più di 100000 link).

partiamo dalla soluzione golosa ...

(leggi di più nel capitolo 3 e oltre.)

Altri strumenti intelligenti

Mi è stato anche detto che Debian usa uno strumento per rendere i suoi CD di distribuzione più intelligenti delle mie distributeraccolte di pacchetti wrt: i suoi risultati sono più belli perché si preoccupano delle dipendenze tra pacchetti e proverebbero a fare la raccolta di pacchetti che va avanti il primo disco chiuso in dipendenze, cioè nessun pacchetto dal 1o disco dovrebbe richiedere un pacchetto da un altro disco (o almeno, direi, il numero di tali dipendenze dovrebbe essere ridotto al minimo).


1

backup2l può fare molto di questo lavoro. Anche se non si utilizza direttamente il pacchetto, è possibile ottenere alcune idee di script da esso.


0

L' rararchiviatore può essere incaricato di dividere automaticamente l'archivio che crea in blocchi di una dimensione specifica con la -vsizebandiera.

Archiviare l'albero di directory denominato fooin blocchi, ad esempio, 500 megabyte ciascuno che si specifica
rar a backup.rar -v500m foo/


2
Di perché rar? tar (+ bz2) + split è un approccio più nativo per * nix.
camper

Gli "alberi delle dimensioni di un morso" non sembrano del tutto simili rar, a meno che non scompaia di nuovo ogni "parte" nella sua directory, che ovviamente non funzionerà, poiché le parti non sono progettate in questo modo e non si dividono sui confini dei file.
MattBianco,

1
Se si parla di strumenti che danno risultati simili a tar+ split, allora c'è anche dar ; ecco la nota sulla sua caratteristica rilevante: "(SLICES) è stato progettato per poter dividere un archivio su più supporti rimovibili qualunque sia il loro numero e qualunque sia la loro dimensione". Rispetto a tar+ split, suppongo, consente alcuni modi più semplici per accedere ai file archiviati. (A proposito, ha anche una funzione simile a distribute"BACKUP DIFFERENZIALE" e "ISTANTANEA DI ALBERO DI DIRECTORY", ma potrebbe non piacere che il risultato sia un formato speciale, non un ISO con un albero di dir.)
imz - Ivan Zakharyaschev
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.