Implementar algo assim pode ser difícil como uma primeira tentativa, se você se importa com os arquivos e não quer estragar. Então, aqui estão algumas alternativas para escrever um script completo no bash. Estas são linhas de comando mais ou menos complexas (oneliners) que podem ajudar na sua situação.
Há uma incerteza em sua pergunta: você quer comparar cada arquivo na origem com todo arquivo em dest ou somente aqueles com nomes de arquivos "correspondentes"? (Isso seria comparar /path/to/src/a
com /path/to/dest/a
e /path/to/src/b
com /path/to/dest/b
, mas não /path/to/src/a
com /path/to/dest/b
e assim por diante)
Suponho que você queira apenas comparar arquivos com caminhos correspondentes !!
primeira ideia: diff
O bom e velho diff
pode comparar diretórios recursivamente. Também use a opção -q
para ver quais arquivos diferem e não como eles diferem.
diff -r -q /path/to/source /path/to/dest
cons
- Isso pode levar um tempo longo dependendo do tamanho do seu disco rígido.
- Isso não exclui os arquivos antigos.
- A saída não é facilmente analisável
pros
- Isso não exclui nenhum arquivo:)
Então, após confirmar manualmente / visualmente que não há diferenças em nenhum arquivo de seu interesse, você deve excluir manualmente a origem com rm -rf /path/to/source
.
segunda ideia: rsync
(editar: isso pode ser o melhor agora)
rsync
é o mestre de todas as ferramentas de linha de comando de cópia (na minha opinião). Como mencionado nos comentários da sua pergunta, ele tem uma opção --checksum
, mas também tem um bulkload de outras opções. Pode transferir arquivos de local para remoto, de remoto para local e de local para local. Uma das características mais importantes, na minha opinião, é que se você der as opções corretas, você pode abortar e reiniciar o comando (executar a mesma linha de comando novamente) e continuará de onde saiu!
Para o seu objetivo, as seguintes opções podem ser interessantes:
-
-v
: verbose, mostre o que acontece pode ser dado várias vezes, mas normalmente uma é suficiente -
-n
: corrida seca, muito importante para testar coisas, mas não faça nada (combine com-v
) !! -
-c
: use a soma de verificação para decidir o que deve ser copiado -
--remove-source-files
: remove arquivos que foram transferidos com sucesso (apontado por @brawny84, eu não sabia e não o encontrei na página man na minha primeira leitura)
Portanto, este comando sobrescreverá todos os arquivos em dest
que tenham uma soma de verificação diferente do arquivo correspondente em source
(correspondente por nome).
rsync -a -c -v --remove-source-files -n /path/to/source /path/to/dest
rsync -a -c -v --remove-source-files /path/to/source /path/to/dest
pros
- funciona com somas de verificação
- tem um modo de execução a seco
- copia todos os arquivos e arquivos ausentes que diferem da origem para o destino
- pode ser interrompido e reiniciado
- tem uma opção de exclusão para ignorar alguns arquivos em src se você não quiser copiar todos os arquivos
- pode excluir arquivos de origem transferidos
cons
- ??
terceira ideia: fdupes
O programa fdupes
Eu projetei listar arquivos duplicados. Ele verifica o md5sums por padrão.
pros
- usa o md5 para comparar arquivos
- tem uma opção
--delete
para excluir uma das duplicatas
cons
- compara o arquivo each com todos os outros arquivos , assim, se houver arquivos duplicados dentro do próprio destino, ele também os listará
- o modo de exclusão parece ser interativo, você precisa confirmar para cada conjunto de arquivos iguais que podem não ser viáveis para árvores de diretórios grandes
- o modo não interativo excluirá todos os arquivos, exceto o primeiro, de cada conjunto de arquivos iguais. Mas não tenho idéia do que é o primeiro arquivo (na origem ou no destino?)
última ideia: passe pela dor de escrever e depurar seu próprio script de shell
Eu começaria com algo assim se tivesse que ser feito manualmente. Eu não testei isso, tente com o ls
primeiro e tente descobrir se ele irá quebrar alguma coisa !!
#!/bin/bash
# first require that the source and dest dirs
# are given as arguments to the script.
src=${1:?Please give the source dir as first argument}
dest=${2:?Please give the destination dir as second argument}
# go to the source directory
cd "$src"
# This assumes that there are no newlines in filenames!
# first find all plain files in the current dir
# (which should be $src)
# then use xargs to hand the filenames to md5sum
# pipe the md5 sums into a subshell
# go to the dest in the subshell
# read the md5sums from stdin and use md5sum -c to check them
# After the subshell filter lines to only keep those that end in "OK"
# and at the same time remove the "OK" stuff after the file name
# use xargs to hand these file names to ls or rm.
find . -type f | \
xargs md5sum | \
( cd "$dest" && md5sum -c ) | \
sed -n 's/: OK$//p' | \
xargs ls
O ls
na última linha é para listar todos os arquivos que passaram na verificação. Se você substituí-lo por rm
, eles serão removidos do diretório de origem (o diretório atual após o cd "$src"
).