segunda-feira, 22 de julho de 2013

Backup entre pen-drive e HD

Sempre fiz o mesmo procedimento com relação aos trabalhos feitos na faculdade: o que era produzido nos laboratórios era armazenando no meu pen-drive e este conteúdo copiado para o meu computador pessoal. O problema é que às vezes eu esquecia de fazer a segunda etapa e ao longo de um semestre é certo acumular uma quantidade expressiva. Simplesmente copiar todos os trabalhos pode sobreescrever algum diretório e assim, perder algum trabalho. A solução é executar o script abaixo.

As variáveis origem e destino representam, respectivamente, o ponto de montagem do pen-drive e o meu userspace o qual armazeno meus dados. É importante que os subdiretórios abaixo deles tenham o mesma estruturação:

 $ find -maxdepth 1
.
./laboratorio_de_hardware
./Dev-Cpp 5.2.0.3 IDE Only Portable.7z
./engenharia_de_software
./ra_ads.txt
./minicurso_C
./sistemas_operacionais
./ihc
./php
./estatistica
./horario_de_aulas.odt
./contabilidade

O primeiro passo é fazer todo levantamento dos diretórios e arquivos da origem e destino.

Em seguida, o script separa o que é comum a ambos dentro do arquivo /tmp/comum.txt e o que precisa ser copiado em /tmp/inexistente.txt.

Se há algo a ser copiado são exibidas mensagens contabilizando quantos arquivos são comuns, quantos serão copiados e a quantidade em kB a ser copiado. Todos os diretórios que não existem na variável destino (computador) são criados pois causa um erro se tentar copiar para um diretório que não existe. Depois, é necessário preparar um arquivo que contenha o caminho dos arquivos que serão copiados para o HD. Para tal fim, o sed substitui o valor de $origem por $destino no arquivo /tmp/inexistente.txt. Desta forma, tudo que não é comum ao HD e ao pen-drive está pronto pronto para ser copiado.

Se não houver diferença entre origem e destino, exibe a mensagem: "$origem" e "$destino" têm os mesmos arquivos.

#!/bin/bash
rm /tmp/*.txt

origem="/media/murilo/FUJITA/fatec"
destino="/home/murilo/fatec/periodo2-1s_2013"

cd "$destino" 
find -type f > /tmp/fatec_hd.txt
cd "$origem" 
find -type f > /tmp/fatec_pendrive.txt

# Tem arquivo no pen-drive que nao existe no HD?
pen_drive_linhas=`wc -l /tmp/fatec_pendrive.txt | cut -f1 -d" "`
for i in `seq $pen_drive_linhas`
  do
    pendrive_arquivo=`head -n $i /tmp/fatec_pendrive.txt | tail -n 1`
    grep "$pendrive_arquivo" /tmp/fatec_hd.txt
    if [ $? -eq 0 ]
      then 
        echo "$pendrive_arquivo" >> /tmp/comum.txt
      else
        echo "$pendrive_arquivo" >> /tmp/inexistente.txt
    fi
  done

if [ -f /tmp/inexistente.txt ]
  then
    # Full path for source
    sed "s,^.,$origem," /tmp/inexistente.txt >> /tmp/inexistente1.txt
    sed 's/^/"/g' /tmp/inexistente1.txt >> /tmp/$$
    sed 's/$/"/g' /tmp/$$ >> /tmp/inexistente3.txt
    rm /tmp/$$
    
    inexistente=`wc -l /tmp/inexistente1.txt | cut -f1 -d" "`
    
    echo `wc -l /tmp/comum.txt | cut -f1 -d" "` arquivos comuns.
    echo $inexistente arquivos que estao no pen-drive e nao estão no HD.
    echo `wc -l /tmp/fatec_pendrive.txt | cut -f1 -d" "` no total.
    
    # Quantidade em kB a ser copiado do pen-drive para o HD
    for i in `seq $inexistente`
      do 
        arquivo_inexistente=`head -n $i /tmp/inexistente1.txt | tail -n 1`
        du -m "$arquivo_inexistente" | awk '{printf "%s\n",$1}' 
      done > /tmp/kB_arquivos.txt
    
    echo `paste -s -d"+" /tmp/kB_arquivos.txt | bc` kB a ser copiado do pen-drive para o HD
    sleep 2
    
    sed "s,^,$origem," /tmp/inexistente1.txt >> /tmp/inexistente2.txt
    sed 's/$/"/g' /tmp/inexistente2.txt >> /tmp/inexistente3.txt
    
    # Checking for absent directories
    for i in `seq $inexistente`
      do
        inexistente_diretorio=`head -n $i /tmp/inexistente3.txt | tail -n 1 | sed 's/"//g'`
        /usr/bin/dirname "$inexistente_diretorio" 
      done >> /tmp/inexistente_diretorio.txt
    
    sort /tmp/inexistente_diretorio.txt >> /tmp/inexistente_diretorio2.txt
    uniq /tmp/inexistente_diretorio2.txt >> /tmp/inexistente_diretorio3.txt
    sed "s,$origem,$destino," /tmp/inexistente_diretorio3.txt >> /tmp/inexistente_diretorio4.txt
    
    echo Criando `wc -l /tmp/inexistente_diretorio4.txt | cut -f1 -d" "` diretorios.
    sleep 2
    
    #Creating the absent directories in destination (hd)
    int_diretory2create=`wc -l /tmp/inexistente_diretorio4.txt | cut -f1 -d" "`
    for i in `seq $int_diretory2create`
      do
        diretory2create=`head -n $i /tmp/inexistente_diretorio4.txt | tail -n 1`
        mkdir -p "$diretory2create"
      done
    
    # replacing source path for destination path
    sed "s,$origem,$destino," /tmp/inexistente1.txt >> /tmp/inexistente_destino1.txt 
    
    # performs the copy process from pen-drive to hd
    for i in `seq $inexistente`
      do
        from=`head -n $i /tmp/inexistente1.txt | tail -n 1`
        destination=`head -n $i /tmp/inexistente_destino1.txt | tail -n 1`
        cp -v "$from" "$destination"
      done 
  else
     echo
     echo
     echo "$origem" e "$destino" têm os mesmos arquivos
fi

Suprimindo a saída com a longa listagem de arquivos, estes são os dados obtidos pelo script e o tempo para realizar as tarefas de levantar os dados da origem e destino, comparar o que precisa ser copiado, criar os todos os diretórios e copiar nos seus devidos lugares:

381 arquivos comuns.
284 arquivos que estao no pen-drive e nao estão no HD.
665 no total.
301 kB a ser copiado do pen-drive para o HD
Criando 51 diretorios.

real 0m9.874s
user 0m0.300s
sys 0m0.844s

Ao executar novamente, a seguinte resposta é obtida:

/media/murilo/FUJITA/fatec e /home/murilo/fatec/periodo2-1s_2013 têm os mesmos arquivos

Conclusão: Não importa quantos arquivos tenham se acumulados ao longo do tempo, este script permite sincronizar os conteúdos em um intervalo de tempo extremamente curto.