Como posso comparar arquivos diferentes sem abri-los?

1

Eu 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. Eu quero comparar, sem abrir qualquer um deles, cada arquivo em A com cada arquivo em B e descobrir se há um arquivo ou mais em um similar a um ou mais arquivos em B. Como posso usar o comando como o seguinte em um loop para pesquisar todos os arquivos?

cmp --silent  file1 file2  || echo "file1 and file2 are different"
    
por Mohsen El-Tahawy 17.05.2016 / 19:32

3 respostas

2

Os aparentes desafios da pergunta / solicitação talvez sejam o aspecto da recursão.

Assumindo que cmp é um utilitário adequado e que ambas as pastas / diretórios 1 & 2 a serem comparados são da mesma estrutura (ou seja, mesmos arquivos e pastas) e residem dentro do 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" ;

ATUALIZAÇÃO:

Seguindo com outro script - após um 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" ;
    
por 18.05.2016 / 03:34
2

Se os arquivos forem exatamente iguais, o md5sum s será exatamente o mesmo, 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) de comprimento e a saída do programa md5sum usa dígitos hexadecimais. Portanto, usamos a opção -w32 no comando uniq para comparar apenas os primeiros 32 caracteres em cada linha.

Isso imprimirá todos os arquivos com um md5sum não exclusivo. ou seja, duplicados.

NOTA: isso detectará arquivos duplicados, não importando onde eles estejam em A / ou B / - assim, se /A/subdir1/file e A/subdir2/otherfile forem iguais, eles ainda serão impressos. Se houver várias duplicatas, elas serão todas impressas.

Você pode remover os md5sums da saída canalizando para, por exemplo, awk '{print $2}' ou com cut ou sed etc. Deixei-os na saída porque eles são uma chave útil para uma matriz associativa (também conhecido como 'hash') em awk ou perl etc para processamento adicional.

    
por 20.05.2016 / 03:23
1

Acho que isso vai te aproximar. Ele listará a saída cmp para todos os arquivos chamados resultados em A, comparados a todos os arquivos chamados resultados em B.

find ./A -name results | xargs -I REPLACESTR find ./B -name results -exec cmp REPLACESTR {} \;
    
por 18.05.2016 / 20:42