O seguinte usa md5
para produzir um resumo MD5 para todos os arquivos no diretório atual ou abaixo:
find . -type f -exec md5 {} +
Substitua md5
por md5sum --tag
se você não tiver o utilitário BSD md5
.
Vamos criar um script simples para fazer isso nos diretórios:
#!/bin/bash
tmpdir=${TMPDIR:-/tmp}
if (( $# != 2 )); then
echo 'Expected two directories as arguments' >&2
exit 1
fi
i=0
for dir in "$@"; do
(( ++i ))
find "$dir" -type f -exec md5 {} + | sort -t '=' -k2 -o "$tmpdir/md5.$i"
done
Isso leva dois diretórios na linha de comando e produz arquivos chamados md5.1
e md5.2
, um arquivo para cada diretório, em /tmp
(ou onde quer que $TMPDIR
esteja apontando). Esses arquivos são classificados no resumo MD5.
Os arquivos serão parecidos com
MD5 (<path>) = <MD5 digest>
com uma dessas linhas para cada arquivo.
Em seguida, no mesmo script, compare a soma de verificação entre os dois arquivos:
join -t '=' -1 2 -2 2 "$tmpdir"/md5.[12]
Isso faz uma operação de "junção" relacional entre os dois arquivos, usando a soma de verificação como o campo de junção. Todas as linhas que tiverem a mesma soma de verificação nos dois campos serão mescladas e produzidas.
Se qualquer soma de verificação for a mesma em ambos os arquivos, será exibida:
<space><MD5 digest>=MD5 (<path1>) =MD5 (<path2>)
Isso pode ser passado para awk
diretamente para analisar os dois caminhos:
awk -F '[()]' 'BEGIN { OFS="\t" } { print $2, $4 }'
O -F [()]
é apenas uma maneira de dizer que gostaríamos de dividir cada linha em campos com base em (
e )
. Isso nos deixa com os caminhos nos campos 2 e 4.
Isso produziria
<path1><tab><path2>
É só uma questão de ler esses pares de caminhos separados por tabulações e emitir os comandos corretos para criar os links:
while IFS=$'\t' read -r path1 path2; do
echo ln -f "$path1" "$path2"
done
Em resumo:
#!/bin/bash
tmpdir=${TMPDIR:-/tmp}
if (( $# != 2 )); then
echo 'Expected two directories as arguments' >&2
exit 1
fi
i=0
for dir in "$@"; do
(( ++i ))
find "$dir" -type f -exec md5 {} + | sort -t '=' -k2 -o "$tmpdir/md5.$i"
done
join -t '=' -1 2 -2 2 "$tmpdir"/md5.[12] |
awk -F '\)|\(' 'BEGIN { OFS="\t" } { print $2, $4 }' |
while IFS=$'\t' read -r path1 path2; do
echo ln -f "$path1" "$path2"
done
rm -f "$tmpdir"/md5.[12]
O echo
no loop while
está lá por segurança. Execute-o uma vez para ver o que aconteceria e remova-o e execute-o novamente se tiver certeza de que está fazendo a coisa certa.
Lembre-se de que links físicos não podem abranger partições. Isso significa que os dois diretórios precisam estar na mesma partição. Os arquivos no diretório segundo serão sobrescritos se forem encontrados duplicados. Mantenha um backup dos originais em algum lugar até ficar satisfeito com o resultado!
Observe que essa solução não funcionará corretamente se algum arquivo tiver (
ou )
ou uma guia em seus nomes de arquivo.