Dividir uma grande árvore de diretórios em pedaços de tamanho especificado?

11

Eu tenho uma árvore de diretórios que gostaria de fazer backup em discos ópticos. Infelizmente, excede o tamanho de qualquer disco (cerca de 60 GB). Estou procurando um script que divida essa árvore em pedaços de tamanho apropriado com links físicos ou outros enfeites (deixando o original intocado). Eu poderia então alimentar essas árvores de tamanho pequeno no processo de backup (adicionar redundância de PAR2, etc.).

Não é um roteiro chique, mas parece que já pode ter sido feito. Sugestões?

(Expandir e escrever em uma etapa é um impedimento, porque quero fazer mais coisas antes que os arquivos sejam gravados.)

Reid
fonte
Você já pensou em contratar um escritor bluray?
BSD
2
A mídia de DVD não é confiável ... Eu recomendaria uma unidade externa, um backup online como o Carbonite ou, se gravar mídia, use alguma par2proteção.
Aaron D. Marasco

Respostas:

7

Existe um aplicativo desenvolvido para isso: dirsplit

Geralmente vive em cdrkitou dirsplitpacotes.

Ele pode criar pastas prontas para uso com links para criar facilmente DVDs com o K3b ou outro software da GUI

Hubert Kario
fonte
Isso funcionou muito bem. No Ubuntu eu encontrei no genisoimagepacote.
nograpes
2

Certa vez, fiz um roteiro feio para um propósito semelhante. É apenas uma brincadeira, mas quando escrevi não me importei com o tempo de execução ou a beleza. Tenho certeza de que existem mais versões "produtificadas" do mesmo conceito, mas se você deseja obter algumas idéias ou algo para começar a invadir, aqui vai (fiz isso em 2008, use por sua conta e risco!): - )

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

Eu acho que o resultado foi compartilhado através do samba para um host do Windows que gravou discos dele. Se você usar o item acima inalterado, poderá usar mkisofsoutro arquivador que resolva links simbólicos.

MattBianco
fonte
Fiz algumas alterações no seu script para lidar com caracteres especiais nos nomes dos arquivos (espaço em branco, traços e pontos iniciais \[?*). Leitura sugerida: não analise a saída de ls , $ VAR vs $ {VAR} e cite ou não . Observe que eu não testei o script resultante. Se você não entender minhas alterações, não hesite em perguntar.
Gilles 'SO- stop be evil' (
@ Gilles: Eu tenho lido bastante desde 2008 ;-) Alterações para tornar o script mais genérico são boas. (Eu não gosto da introdução de [, em oposição a test, embora) ...
Matt Bianco
Você deve minúsculas a maioria dessas variáveis. Por convenção, capitalizamos variáveis ​​de ambiente (PAGER, EDITOR, SHELL, ...) e variáveis ​​internas do shell. Todos os outros nomes de variáveis ​​devem conter pelo menos uma letra minúscula. Esta convenção evita a substituição acidental de variáveis ​​ambientais e internas.
Chris Baixo
2

Certa vez, escrevi um script para resolver um problema semelhante - chamei-o de "distribuir" (você pode ler o código principal do script ou o arquivo com a mensagem de ajuda ou fazer o download como um pacote ); a partir de sua descrição :

distribuir - distribuir uma coleção de pacotes em vários CDs (especialmente para uso futuro com o APT)

Descrição: o programa `distribut 'facilita as tarefas relacionadas à criação de um conjunto de CD para distribuição de uma coleção de pacotes. As tarefas incluem: organizar o sistema de arquivos dos CDs (dividir a grande quantidade de pacotes em vários discos etc.), preparar a coleção para uso pelo APT (indexação), criar imagens ISO e gravar os discos.

Atualizações periódicas da coleção distribuída inicialmente podem ser emitidas com a ajuda de `distribuir '.

Ele executa todo o processo em várias etapas: em uma etapa, cria os "layouts" de disco mais avançados, usando links simbólicos para os arquivos originais - para que você possa intervir e alterar as futuras árvores de disco.

Os detalhes sobre seu uso podem ser lidos na mensagem de ajuda impressa pelo script (ou examinando o código-fonte).

Ele foi escrito com um caso de uso mais complicado em mente (emitir atualizações como um "diff" - o conjunto de novos arquivos adicionados - para a coleção de arquivos gravada originalmente), por isso inclui um estágio inicial extra, a saber, "consertar "o estado atual da coleção de arquivos (por uma questão de simplicidade, ele é replicado pela coleção original de arquivos por meio de links simbólicos) em um local de trabalho especial para salvar os estados da coleção; depois, em algum momento no futuro, ele poderá criar uma diferença entre um estado atual futuro da coleção de arquivos e esse estado salvo). Portanto, embora você possa não precisar desse recurso, não é possível pular esse estágio inicial, o AFAIR.

Além disso, não tenho certeza agora (escrevi alguns anos atrás) se trata bem de árvores complexas ou se deve dividir apenas diretórios de arquivos simples (um nível). (Verifique a mensagem de ajuda ou o código-fonte para ter certeza; também procurarei isso um pouco mais tarde, quando tiver algum tempo.)

O material relacionado ao APT é opcional, portanto, não preste atenção, pois ele pode preparar coleções de pacotes a serem usadas pelo APT, se você não precisar disso.

Se você se interessar, é claro, sinta-se à vontade para reescrevê-lo de acordo com suas necessidades ou sugerir melhorias.

(Observe que o pacote inclui patches úteis adicionais não aplicados na lista de códigos apresentada no repositório Git vinculado acima!)

imz - Ivan Zakharyaschev
fonte
Tenho apresentado --among outras coisas - o trecho de código do distributeque resolve a tarefa essencial feitas sobre aqui.
imz - Ivan Zakharyaschev 30/03
2

Não devemos esquecer que a essência da tarefa é realmente bastante simples; conforme apresentado em um tutorial sobre Haskell (que é escrito sobre o trabalho da solução para esta tarefa, aprimorado de forma incremental)

Agora, vamos pensar por um momento sobre como nosso programa funcionará e expressá-lo em pseudocódigo:

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

Parece razoável? Eu pensei assim.

Vamos simplificar um pouco a nossa vida e supor, por enquanto, que calcularemos o tamanho dos diretórios em algum lugar fora do nosso programa (por exemplo, com " du -sb *") e leremos essas informações no stdin.

(do guia Mochileiros para Haskell, capítulo 1 )

(Além disso, na sua pergunta, você deseja ajustar (editar) os layouts de disco resultantes e usar uma ferramenta para gravá-los.)

Você pode reutilizar (adaptar e reutilizar) uma variante simples do programa desse tutorial Haskell para dividir sua coleção de arquivos.

Infelizmente, na distributeferramenta que eu mencionei aqui em outra resposta , a simplicidade da tarefa divisão essencial não é compensada pela complexidade e bloatedness da interface do usuário de distribute(porque foi escrito para combinar várias tarefas, embora realizada em etapas, mas ainda assim combinada, não da maneira mais limpa que eu conseguia pensar agora).

Para ajudá-lo a usar seu código, aqui está um trecho do código de referência distribute(na linha 380 ) que serve para executar esta tarefa "essencial" de dividir uma coleção de arquivos:

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

( leia mais após a linha 454 )

Observe que a eatFilesfunção prepara os layouts dos futuros discos como árvores nas quais as folhas são links simbólicos para os arquivos reais. Portanto, é um requisito que você possa editar os layouts antes de gravar. O mkisofsutilitário tem uma opção para seguir links simbólicos, que são de fato empregados no código da minha mkisofunção .

O script apresentado (que você pode pegar e reescrever para suas necessidades, é claro!) Segue a idéia mais simples: somar o tamanho dos arquivos (ou, mais precisamente, os pacotes no caso de distribute) apenas na ordem em que foram listados, não faça qualquer rearranjo.

O "Guia do Hitchhikers para Haskell" leva o problema de otimização mais a sério e sugere variantes de programa que tentariam reorganizar os arquivos de maneira inteligente, para que se encaixem melhor em discos (e exijam menos discos):

Já chega de preliminares. vamos embalar alguns CDs.

Como você já deve ter reconhecido, nosso problema é clássico. É chamado de "problema da mochila" ( pesquise no Google , se você ainda não sabe o que é. Existem mais de 100000 links).

vamos começar com a solução gananciosa ...

(leia mais no capítulo 3 e mais).

Outras ferramentas inteligentes

Foi-me dito também que o Debian usa uma ferramenta para tornar seus CDs de distribuição mais inteligentes que minhas distributecoleções de pacotes wrt: seus resultados são melhores porque se preocupam com as dependências entre pacotes e tentam fazer a coleção de pacotes o primeiro disco fechado sob dependências, ou seja, nenhum pacote do 1º disco deve exigir um pacote de outro disco (ou pelo menos, eu diria, o número dessas dependências deve ser minimizado).

imz - Ivan Zakharyaschev
fonte
1

O backup2l pode fazer muito deste trabalho. Mesmo se você não usar o pacote diretamente, poderá obter algumas idéias de script.

Randy Coulman
fonte
0

O rararquivador pode ser instruído a dividir automaticamente o arquivo morto em pedaços de um tamanho específico com a -vsizebandeira.

Arquivar essa árvore de diretórios nomeada fooem pedaços de, digamos, 500 megabytes cada, especificados por você
rar a backup.rar -v500m foo/

Shadur
fonte
2
Do que por que rar? tar (+ bz2) + split é uma abordagem mais nativa para * nix.
RVS
"árvores pequenas" não parece muito rar , a menos que você descompacte cada "parte" novamente em seu próprio diretório, o que obviamente não funcionará, pois as partes não foram projetadas dessa maneira e não são divididas nos limites do arquivo.
Matt Bianco
11
Se estiver falando sobre ferramentas que dão resultados semelhantes a tar+ split, também há dar ; aqui está a observação sobre seu recurso relevante: "(SLICES) foi projetado para ser capaz de dividir um arquivo em várias mídias removíveis, independentemente do número e do tamanho". Comparado a tar+ split, presumo, ele permite algumas maneiras mais fáceis de acessar os arquivos arquivados. (BTW, também possui um recurso semelhantedistribute : "BACKUP DIFERENCIAL" e "INSTANTÂNEO DE ÁRVORE DIRETÓRIO", mas é possível que não goste que o resultado seja um formato especial, não um ISO com uma árvore de diretórios.)
imz - Ivan Zakharyaschev