Dadas duas árvores de diretório, como posso descobrir quais arquivos diferem por conteúdo?

786

Se eu quiser encontrar as diferenças entre duas árvores de diretório, normalmente apenas executo:

diff -r dir1/ dir2/

Isso mostra exatamente quais são as diferenças entre os arquivos correspondentes. Estou interessado em obter apenas uma lista dos arquivos correspondentes cujo conteúdo é diferente. Eu assumi que isso seria simplesmente uma questão de passar uma opção de linha de comando diff, mas não consegui encontrar nada na página de manual.

Alguma sugestão?

Mansoor Siddiqui
fonte
1
Com relação a um dos diretórios, como obter apenas os arquivos / diretórios extras no outro?
Sandeepan Nath
use dircmpcomando no unix (não linux)
roblogic

Respostas:

1119

Você disse que Linux, então você teve sorte (pelo menos ele deve estar disponível, não tenho certeza quando foi adicionado):

diff --brief --recursive dir1/ dir2/ # GNU long options
diff -qr dir1/ dir2/ # common short options

Deve fazer o que você precisa.

Se você também deseja ver diferenças nos arquivos que podem não existir nos dois diretórios:

diff --brief --recursive --new-file dir1/ dir2/ # GNU long options
diff -qrN dir1/ dir2/ # common short options
Mark Loeser
fonte
12
Agradável. Mas mais curto é diff -qr dir1/ dir2/e minha versão estendida paradiff -qr dir1/ dir2/ | grep ' differ'
sobi3ch
1
@skv why? É o mesmo comando que resposta. Eu mudei apenas --briefpara o atalho -q.
Sobi3ch #
2
@skv Não é exatamente o que a pergunta original fez, mas atualizou a resposta para acomodar essa pergunta também.
22615 Mark-Loeser
3
@MikeMaxwell Precisa ser --brief. -briefé interpretado como -b -r -i -e -f, em outras palavras, como um conjunto de sinalizadores, não como uma única opção.
Daboross 25/10/19
2
@daboross: uau, estou usando o Unix / Linux há um bom tempo, e nunca percebi que havia essa distinção entre '-' e '-'. (Acho que não existia '-' quando comecei.) Obrigado pela explicação!
Mike Maxwell
287

O comando que eu uso é:

diff -qr dir1/ dir2/

É exatamente o mesmo que o de Mark :) Mas a resposta dele me incomodou, pois usa diferentes tipos de sinalizadores, e me fez olhar duas vezes. Usando os sinalizadores mais detalhados de Mark, seria:

diff  --brief --recursive dir1/ dir2/

Peço desculpas por postar quando a outra resposta for perfeitamente aceitável. Não consegui me parar ... trabalhando em ser menos pedante.

FPC
fonte
3
aprecie totalmente a consistência - mas não se sinta mal; Eu upvoted resposta de Mark também;)
Gerard ONeill
10
..so faz sentido tu colocar respostas diferentes com APENAS um sabor diferente? IMHO não! Faz sentido que você combine as duas respostas a uma resposta consistente? sim! ;)
sobi3ch
1
Só uma pergunta; o que qsignifica? É uma abreviação de alguma coisa? Não consigo encontrar qualquer lógica por trás da q..
kramer65
3
@ kramer65 - é o mesmo que "--brief", mas acho que você se pergunta por que q? Talvez para rápido? "-b" é interpretado por "ignorar alterações na quantidade de espaço em branco", de acordo com a página do manual.
FPC
4
@ kramer65 Eu acredito que qé para quiet, geralmente significando menos detalhado.
Gogeta70
105

Eu gosto de usar git diff --no-index dir1/ dir2/, porque ele pode mostrar as diferenças de cor (se você tiver essa opção definida na sua configuração do git) e porque mostra todas as diferenças em uma saída paginada longa usando "less".

Alan Porter
fonte
25
Arrumado. Quem imaginaria que o git pode diferenciar diretórios arbitrários, não apenas o repositório de seus arquivos?
Dan Dascalescu
2
O colordiff de script Perl é muito útil aqui, pode ser usado com svn e diff normal.
Felipe Alvarez
4
Se você comparar (como eu) 2 dirs como projetos / repositórios Git separados, precisará adicionar --no-indexmais em stackoverflow.com/a/1792477/473390 . Atualizei a resposta @ alan-porter.
Sobi3ch 7/08
Eu gosto deste, também acho que se você adicionar --name-status à linha de comando, ela mostrará apenas a lista de nomes de arquivos com sinalizadores "M / A / D" para o status Modificado / Adicionado / Excluído.
gzh 27/02
Isso acontece para que os dois diretórios realmente contenham a pasta .git, como posso excluí-la da comparação?
Muhamed Cicak 28/03
35

Esses dois comandos fazem basicamente a coisa solicitada:

diff --brief --recursive --no-dereference --new-file --no-ignore-file-name-case /dir1 /dir2 > dirdiff_1.txt

rsync --recursive --delete --links --checksum --verbose --dry-run /dir1/ /dir2/ > dirdiff_2.txt

A escolha entre eles depende da localização de dir1 e dir2:

Quando os diretórios residem em duas unidades separadas, o diff supera o rsync. Mas quando os dois diretórios comparados estão na mesma unidade, o rsync é mais rápido. Isso porque o diff coloca uma carga quase igual nos dois diretórios em paralelo, maximizando a carga nas duas unidades.

O rsync calcula somas de verificação em blocos grandes antes de compará-los. Isso agrupa as operações de E / S em grandes blocos e leva a um processamento mais eficiente quando as coisas acontecem em uma única unidade.

CodeBug
fonte
3
rsync não é apenas mais rápido para arquivos em unidades individuais, mas também allowes para comparar arquivos em subdiretórios, por exemplo rsync --options /usr /bin /var /sbin /lib /old_rootefetivamente comparar raiz atual /(especificando todos os subdiretórios no mesmo) e /old_root(contendo, por exemplo, algum apoio mais antiga /), que é algo diff -rlata faça. E se você presumir que arquivos com o mesmo tamanho, permissões e carimbos de data / hora provavelmente não foram alterados, deixar de fora --checksumfornecerá uma verificação extremamente rápida (se não for o caso) de quais arquivos podem ter sido alterados.
Matija Nalis 19/08/19
1
Qual é o propósito de --deletecom rsync?
Tom Hale
2
O objetivo do --delete é excluir os arquivos existentes no destino-dir que não são (já) presente no source-dir
Thomas Munk
2
Neste caso (com a --dry-runbandeira) nada é realmente apagado, rsyncapenas impressões quais arquivos estão em dir1, mas não em dir2
mata
11
Eu recomendo colocar o --dry-runprimeiro sempre para não esquecê-lo acidentalmente.
Dave Rager
22

O Meld também é uma ótima ferramenta para comparar dois diretórios:

meld dir1/ dir2/

O Meld tem muitas opções para comparar arquivos ou diretórios. Se dois arquivos diferirem, é fácil entrar no modo de comparação de arquivos e ver as diferenças exatas.

Alexander
fonte
2
Agradável. Eu escrevi um script perl simples para realizar comparação sobre árvores, mas estou atingindo limitações. Este parece ser o bilhete.
David Tonhofer
O único problema é que ele não se presta a scripts, pois é um aplicativo gráfico. Mas é bom se você não se importa com a GUI! Obrigado.
DeanM
Acho que isso meldse torna terrivelmente lento se usado em diretórios grandes. Existe algo que lide com diretórios grandes melhor?
Popup
@ Popup, não que eu saiba. Você pode encontrar diferentes nomes de arquivos com algo parecido com isto:find dir1 dir2 | cut -d/ -f2- | sort | uniq --unique
Alexander
1
@ Alexander - Nesse caso, acho que meld <(find dir1 -ls ) <(find dir2 -ls)funciona muito bem, usando a substituição do processo bash. (zsh da =(command)funciona ainda melhor.)
Popup
10

O 'faturamento' do compatriota de canal (da freenode / # centos fame) compartilhou seu método comigo:

diff -Naur dir1/ dir2

Incluir a barra final do diretório final não importa.

Além disso, parece que a -uopção não está disponível em algumas versões mais antigas / de servidor do diff.

A diferença de diferenças:

# diff -Nar /tmp/dir1 /tmp/dir2/
diff -Nar /tmp/dir1/file /tmp/dir2/file
28a29
> TEST

# diff -qr /tmp/dir1/ /tmp/dir2/
Files /tmp/dir1/file and /tmp/dir2/file differ
todd_dsm
fonte
2
Então é isso --new-file/-Nque faz o diff considerar que os arquivos ausentes estão vazios e --text/-aque faz com que ele considere toda a entrada binária como texto. Não vejo as vantagens deste caso de uso específico.
Php #
4

O Diffoscope é uma excelente ferramenta de comparação de diretório baseada em linha de comando.

Eu gosto especialmente que ele pode ser diferente em arquivos:

Ele irá descompactar recursivamente arquivos de vários tipos e transformar vários formatos binários em uma forma mais legível por humanos para compará-los. Ele pode comparar dois tarballs, imagens ISO ou PDF com a mesma facilidade.

Ele não apenas informará quais arquivos diferem, mas também como eles diferem.

nh2
fonte
4

Para encontrar o diff, use este comando:

diff -qr dir1/ dir2/

-r também difere todos os subdiretórios -q diz ao diff para relatar apenas quando os arquivos diferem.

diff  --brief dir1/ dir2/

--brief mostrará os arquivos que dosent existem no diretório

Se não

podemos usar o Meld, que mostrará na janela gráfica que é fácil encontrar a diferença.

meld  dir1/ dir2/
Javeed Shakeel
fonte
2
--briefe -qsão a mesma opção. Sua declaração faz parecer que são diferentes, mas não são.
Elijah Lynn
2

Você também pode usar Rsynce find. Para find:

find $FOLDER -type f | cut -d/ -f2- | sort > /tmp/file_list_$FOLDER

Mas arquivos com os mesmos nomes e nas mesmas subpastas, mas com conteúdo diferente, não serão mostrados nas listas.

Se você é um fã de GUI, pode verificar Meld que @Alexander mencionou. Funciona bem no Windows e no Linux.

Fábio
fonte
1

Relatar diferenças entre dirA e dirB, além de atualizar / sincronizar.

rsync -auv <dirA> <dirB>

Kickaha
fonte