Compare diretórios, mas não o conteúdo dos arquivos

21

Com diff -r eu posso executar esta tarefa, no entanto, leva muito tempo porque o diff verifica o conteúdo do arquivo.

Eu quero algo que determine que dois arquivos são iguais em relação ao tamanho, última modificação etc. Mas não é possível verificar pouco a pouco o arquivo (por exemplo, um vídeo leva tanto tempo)

Existe alguma outra maneira?

eez0
fonte

Respostas:

20

O rsync, por padrão, compara apenas os metadados do arquivo.

rsync -n -a -i --delete source/ target/

explicação:

  • -n na verdade, não copie ou exclua <- ISSO É IMPORTANTE !! 1
  • -a compare todos os metadados do arquivo, como carimbo de data e hora e atributos
  • -i imprimir uma linha de informações por arquivo
  • --delete também relatam arquivos que não estão na fonte

nota: é importante acrescentar os nomes dos diretórios com uma barra. isso é uma coisa rsync.

se você também quiser ver linhas impressas para arquivos idênticos, forneça -iduas vezes

rsync -n -a -ii --delete source/ target/

saída de exemplo:

*deleting   removedfile   (file in target but not in source)
.d..t...... ./            (directory with different timestamp)
>f.st...... modifiedfile  (file with different size and timestamp)
>f+++++++++ newfile       (file in source but not in target)
.f          samefile      (file that has same metadata. only with -ii)

lembre-se de que o rsync compara apenas metadados. isso significa que, se o conteúdo do arquivo for alterado, mas os metadados permanecerem os mesmos, o rsync informará que o arquivo é o mesmo. este é um cenário improvável. portanto, confie que, quando os metadados são os mesmos, os dados são os mesmos ou você precisa comparar os dados dos arquivos pouco a pouco.

bônus: para obter informações sobre o progresso, consulte aqui: Estimativa de tempo ou trabalho restante para concluir o rsync?

lesmana
fonte
1
As barras source/e target/também são muito importantes! (Sem eles, você comparará os nomes dos diretórios de origem e de destino com os nomes dos arquivos filhos, para que todos os nomes de arquivos sejam diferentes.)
peschü
Eu gostaria de ter lido seu comentário anteriormente, isso é tão importante! Omiti a barra apenas na fonte e fiquei pensando por que os arquivos no destino não apareciam como *deleting, mas os arquivos que estão na fonte só apareciam. As barras são fáceis de esquecer acidentalmente e você obtém uma saída plausível, mas errada.
user643011 27/08
3

Utilizar a -q( --briefopção) com diff -r( diff -qr). Na infopágina do GNU diff:

1.6 Resumindo quais arquivos diferem

Quando você deseja apenas descobrir se os arquivos são diferentes e não se importa com as diferenças, pode usar o formato de saída resumido. Nesse formato, em vez de mostrar as diferenças entre os arquivos, a opção diff' simply reports whether files differ. The--brief '(`-q') seleciona esse formato de saída.

Esse formato é especialmente útil ao comparar o conteúdo de dois diretórios. Também é muito mais rápido do que fazer comparações linha a linha normais, porque o `diff 'pode parar de analisar os arquivos assim que souber que existem diferenças.

Isso não compara linha por linha, mas o arquivo como um todo, o que acelera bastante o processador (o que você está procurando).

laebshade
fonte
1
O problema de - q é que ele compara o normal e, quando a diferença é interrompida (se o modo normal continuar comparando), portanto, se os arquivos grandes forem iguais, isso durará muito.
eez0
2

Aqui está um script python rápido que verifica se os nomes de arquivos, mtimes e tamanhos de arquivo são todos iguais:

import os
import sys

def getStats(path):
    for pathname, dirnames, filenames in os.walk(path):
        for filename in ( os.path.join(pathname, x) for x in filenames ):
            stat = os.stat(filename)
            yield filename[len(path):], stat.st_mtime, stat.st_size

sys.exit(tuple(getStats(sys.argv[1])) != tuple(getStats(sys.argv[2])))
Chris Down
fonte
1

Se você só precisa saber se os arquivos de duas ramificações do sistema de arquivos são diferentes (sem consultar os arquivos internos), é possível fazer algo assim:

find /opt/branch1 -type f | sort | xargs -i md5sum {} >/tmp/branch1;
find /opt/branch2 -type f | sort | xargs -i md5sum {} >/tmp/branch2;
diff /tmp/branch1 /tmp/branch2;

HTH

Chaky
fonte
0

Baseado no roteiro de Chris Down, esse roteiro é um pouco mais "visual". Chamando-o com dois argumentos folder1e folder2, ele percorre a primeira pasta e, para cada arquivo, procura um arquivo correspondente na segunda pasta. Se for encontrado, o caminho relativo será impresso em verde, se tiverem tempo ou tamanho modificados diferentes, será impresso em amarelo e, se não for encontrado, será impresso em vermelho.

#!/usr/bin/env python

import os
import sys
from termcolor import colored

def compare_filestats(file1,file2):
    """
    Compares modified time and size between two files.
    Return:
        -1 if file1 or file2 does not exist
         0 if they exist and compare equal
         1 if they have different modified time, but same size
         2 if they have different size, but same modified time
         3 if they have different size, and different modified time
    """

    if not os.path.exists(file1) or not os.path.exists(file2):
        return -1

    stat1 = os.stat(file1)
    stat2 = os.stat(file2)

    return (stat1.st_mtime != stat2.st_mtime) \
        + 2*(stat1.st_size != stat2.st_size)

def compare_folders(folder1,folder2):
    """
    folder1: serves as reference and will be walked through
    folder2: serves as target and will be querried for each file in folder1

    Prints colored status for each file in folder1:
        missing: file was not found in folder2 
        mtime  : modified time is different
        size   : filesize is different
        ok     : found with same filestats
    """
    for dirpath, dirnames, filenames in os.walk(folder1):
        for file1 in ( os.path.join(dirpath, x) for x in filenames ):
            relpath = file1[len(folder1):]
            file2 = os.path.join( folder2, relpath )
            comp = compare_filestats(file1,file2)

            if comp < 0:
                status = colored('[missing]','red')
            elif comp == 1:
                status = colored('[mtime  ]','yellow')
            elif comp >= 2:
                status = colored('[size   ]','yellow')
            else:
                status = colored('[ok     ]','green')

            print status, relpath

if __name__ == '__main__':
    compare_folders(sys.argv[1],sys.argv[2])

Observe que isso não é suficiente para decidir se as duas pastas são iguais; você precisará executá-lo nos dois sentidos para garantir. Na prática, se você quiser apenas saber se as pastas são iguais , o script de Chris é melhor. Se você quiser saber o que está faltando ou é diferente de uma pasta para outra , meu script informará.

NOTA: você precisará do termcolor instalado pip install termcolor,.

Sheljohn
fonte
0

Se você quiser comparar apenas uma estrutura e algumas informações básicas sobre arquivos, tente algo como isto:

diff <(cd $DIR1 && ls -laR) <(cd $DIR2 && ls -laR)

Eu não testei, então qualquer edição é bem-vinda :)

Volodymyr
fonte
2
Isso não funcionará, pois os nomes dos diretórios também estarão nos resultados.
Chris Baixo
e se excluirmos a primeira coluna com nomes de diretório? como <(ls -laR | awk '{$ 1 = ""; print}')
Volodymyr
Nem todas as linhas são nomes de diretório, portanto isso não funcionará corretamente.
Chris Baixo
Aproveite o fato de que cada um <()tem seu próprio ambiente. Editado.
a CVn