Extraia arquivos idênticos de dois diretórios

Extraia arquivos idênticos de dois diretórios

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.2ou -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

sumgera 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. md5sumtambé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, cmpos 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

informação relacionada