
Estou procurando uma solução Linux para o seguinte problema:
Dados dois diretórios com um grande número de arquivos. Todos os nomes de arquivos são aleatórios e diferentes em ambos os diretórios. Entretanto, o conteúdo de alguns dos arquivos nos dois diretórios é idêntico.
Quero copiar todos os arquivos que ocorrem em ambos os diretórios para um terceiro diretório. ("Ocorrer em ambos" significa ter o mesmo conteúdo e não o mesmo nome.)
Responder1
Supondo que seus nomes de arquivos não tenham espaços em branco e não haja subdiretórios em nenhum dos diretórios, o seguinte imprimirá pares de nomes de arquivos com somas MD5 correspondentes:
join -o 1.2,2.2 <(md5sum $D1/* | sort) <(md5sum $D2/* | sort)
Para obter apenas um dos nomes de arquivo, use -o 1.2
ou -o 2.2
.
Se nomes de arquivos (ou caminhos) incluírem espaços em branco, você precisará ser mais inteligente.
Se um único diretório tiver o mesmo arquivo com mais de um nome, você também precisará ser mais inteligente - e decidir exatamente o que fazer. Uma possibilidade seria filtrar as duplicatas antes de fazer a junção:
join -o 1.2,2.2 <(md5sum $D1/* | sort | uniq -w16) \
<(md5sum $D2/* | sort | uniq -w16)
NÃO USEsum
sum
gera uma soma de verificação de 16 bits; se você tiver algumas centenas de arquivos em cada diretório, é provável que obtenha um falso positivo se comparar somas de verificação de 16 bits. md5sum
também não é absolutamente seguro, mas as chances de uma colisão com somas de verificação de 128 bits são mínimas. Em caso de dúvida, e se for realmente importante, cmp
os arquivos também:
join -o 1.2,2.2 <(md5sum $D1/* | sort) <(md5sum $D2/* | sort) |
while read F1 F2; do
if cmp -s $F1 $F2; then
cp F1 $D3
fi
done
(Novamente, isso não funcionará se os arquivos tiverem espaços em branco em seus nomes.)
Responder2
Usando seu shell favorito para este pseudocódigo:
cd D1; sum * | while read l; do echo "D1 $l"; done >/tmp/foo
cd D2; sum * | while read l; do echo "D2 $1"; done >>/tmp/foo
sort -n /tmp/foo | awk '
$1 == prev_cs { echo "cp $3 dest"}
/prev_cs = $1/
' | shell
Você pode salvar a saída do awk para revisão antes de emitir as cópias, se desejar
Responder3
isso pode funcionar, como acontece com o mpez0 para copiar os dups.
find {tst1,tst2} -exec sum {} {} \; 2> /dev/null | sort | uniq