
Tenho dois diretórios A e B; cada um contém muitos subdiretórios
geom001, geom002 ....etc
cada subdiretório contém um arquivo chamado resultados. Quero comparar, sem abrir nenhum deles, cada arquivo em A com cada arquivo em B e descobrir se existe um arquivo ou mais em A semelhante a um ou mais arquivos em B. Como posso usar comandos como o seguinte em um loop para pesquisar todos os arquivos?
cmp --silent file1 file2 || echo "file1 and file2 are different"
Responder1
Se os arquivos forem exatamente iguais, então seus md5sum
s serão exatamente iguais, então você pode usar:
find A/ B/ -type f -exec md5sum {} + | sort | uniq -w32 -D
Um md5sum tem sempre exatamente 128 bits (ou 16 bytes ou 32 dígitos hexadecimais) e a md5sum
saída do programa usa dígitos hexadecimais. Portanto, usamos a -w32
opção do uniq
comando para comparar apenas os primeiros 32 caracteres de cada linha.
Isto irá imprimirtodosarquivos com um md5sum não exclusivo. ou seja, duplicatas.
NOTA: isso detectará arquivos duplicados, não importa onde eles estejam em A/ ou B/ - portanto, se /A/subdir1/file
e A/subdir2/otherfile
forem iguais, eles ainda serão impressos. Se houver várias duplicatas, todas serão impressas.
Você pode remover os md5sums da saída canalizando, por exemplo, awk '{print $2}'
ou com cut
ou sed
etc. Eu os deixei na saída porque eles são uma chave útil para uma matriz associativa (também conhecida como 'hash') em awk
ou perl
etc para mais em processamento.
Responder2
Acho que isso vai te aproximar. Ele listará a saída cmp para todos os arquivos nomeados resultados em A em comparação com todos os arquivos nomeados resultados em B.
find ./A -name results | xargs -I REPLACESTR find ./B -name results -exec cmp REPLACESTR {} \;
Responder3
Os aparentes desafios da pergunta/solicitação talvez sejam o aspecto da recursão.
Supondo que cmp
seja um utilitário adequado e que ambas as pastas/diretórios 1
e 2
a serem comparados tenham a mesma estrutura (ou seja, os mesmos arquivos e pastas) e residam no mesmo caminho raiz - você pode tentar algo semelhante a:
#!/bin/bash
ROOT=$PWD ; # #// change to absolute path eg: /home/aphorise/my_files
PWD1="1/*" ;
PWD2="2/*" ;
# #// Get lengths of seperators
IFS=/ read -a DP <<< ${ROOT} ;
PLEN1=${#DP[*]} ;
IFS=/ read -a DP <<< ${PWD1} ;
PLEN1=$(echo "${#DP[*]}" + $PLEN1 - 1 | bc) ;
IFS=/ read -a DP <<< ${PWD2} ;
PLEN2=${#DP[*]} ;
# #// Set absolute paths:
PWD1="${ROOT}/${PWD1}" ;
PWD2="${ROOT}/${PWD2}" ;
DIFFS=0 ;
function RECURSE()
{
for A_FILE in $1 ; do
if [ -d $A_FILE ] ; then
RECURSE "$A_FILE/*" ;
else
IFS=/ read -a FP <<< ${A_FILE} ;
B_FILE="${PWD2:0:${#PWD2}-${#PLEN2}}$( IFS=/ ; printf "%s" "${FP[*]:$PLEN1:512}"; )" ;
if ! cmp ${A_FILE} ${B_FILE} 1>/dev/null ; then printf "$A_FILE --> $B_FILE <-- DIFFER.\n" ; ((++DIFFS)) ; fi ;
fi ;
done ;
}
printf "Starting comparison on $PWD1 @ $(date)\n\n" ;
RECURSE "${PWD1[*]}" ;
if ((DIFFS != 0)) ; then printf "\n= $DIFFS <= differences detected.\n" ; fi ;
printf "\nCompleted comparison @ $(date)\n" ;
ATUALIZAR:
Seguindo com outro script - após feedback adicional recebido - para comparar incondicionalmente todos os arquivos no diretório 1
com 2
:
#!/bin/bash
PWD1="$PWD/1/*" ;
PWD2="$PWD/2/*" ;
DIFFS=0 ;
NODIFFS=0 ;
printf "Starting comparison on $PWD1 @ $(date)\n\n" ;
FILES_A=$(find ${PWD1} -type f) ;
FILES_B=$(find ${PWD2} -type f) ;
for A_FILE in ${FILES_A[*]} ; do
for B_FILE in ${FILES_B[*]} ; do
if ! cmp ${A_FILE} ${B_FILE} 1>/dev/null ; then
printf "$A_FILE & $B_FILE <- DIFFER.\n" ;
((++DIFFS)) ;
else
printf "\n-> SAME: $A_FILE & $B_FILE\n" ;
((++NODIFFS)) ;
fi ;
done ;
done ;
printf "\n= $DIFFS <= differences detected - & - $NODIFFS <= exact matches.\n" ;
printf "\nCompleted comparison @ $(date)\n" ;