diff para gerar apenas os nomes dos arquivos

244

Estou procurando executar um comando Linux que compare recursivamente dois diretórios e produza apenas os nomes dos arquivos diferentes. Isso inclui qualquer coisa que esteja presente em um diretório e não no outro ou vice-versa e diferenças de texto.

barfoon
fonte

Respostas:

375

Na página do manual diff:

-q   Relate apenas se os arquivos diferem, não os detalhes das diferenças.
-r   Ao comparar diretórios, compare recursivamente todos os subdiretórios encontrados.

Comando de exemplo:

diff -qr dir1 dir2

Exemplo de saída (depende da localidade):

$ ls dir1 dir2
dir1:
same-file  different  only-1

dir2:
same-file  different  only-2
$ diff -qr dir1 dir2
Files dir1/different and dir2/different differ
Only in dir1: only-1
Only in dir2: only-2
John Kugelman
fonte
Obrigado - a diffpágina de manual no CentOS 7 descreve -qcomo "reportar apenas quando os arquivos diferem", o que é menos claro do que o que você escreveu.
Chap
2
Isso compara o conteúdo real dos arquivos, que geralmente é o que se deseja, no entanto, a resposta rsync oferece a opção de examinar apenas os nomes e tamanhos dos arquivos, e não o conteúdo; isso às vezes é desejável.
steveb 13/02/19
Também funciona no macOS.
Marius Soutier
Além disso, pode incluir -x PATTERNno comando para excluir determinados subdiretórios. Por exemplo, diff -qr repo1 repo2 -x ".git" comparará dois diretórios, mas excluirá os caminhos de arquivo com ".git" neles.
ViFI 16/04
27

Você também pode usar o rsync

rsync -rv --size-only --dry-run /my/source/ /my/dest/ > diff.out
boksiora
fonte
6
--size-onlyperderá arquivos de tamanho idêntico, mas com conteúdo diferente, por exemplo, old / version.txt "29a" new / version.txt "29b" . Use em vez disso: rsync -ric --dry-run old/ new/onde o argumento "-i" permite obter a lista de arquivos diretamente viarsync -ric --dry-run old/ new/ | cut -d" " -f 2
iolsmit
6
Isso é ótimo se você estiver procurando apenas arquivos ausentes (principalmente entre compartilhamentos de rede), porque não compara o conteúdo. Isso me ajudou a encontrar alguns arquivos que falharam ao migrar para um novo NAS.
excesso de zelo
4
Certifique-se de incluir a barra final nos caminhos especificados na linha de comando do rsync. Sem eles, isso não funcionará corretamente e o rsync provavelmente apenas enumerará todos os nomes de arquivos!
22417 Vladimir Panteleev #
2
Com relação aos comentários sobre a não verificação do conteúdo. Às vezes é desejável, pelo menos como primeira passagem.
13139 steveb
13

Se você deseja obter uma lista de arquivos que estão apenas em um diretório e não seus subdiretórios e apenas seus nomes de arquivo:

diff -q /dir1 /dir2 | grep /dir1 | grep -E "^Only in*" | sed -n 's/[^:]*: //p'

Se você deseja listar recursivamente todos os arquivos e diretórios diferentes com seus caminhos completos:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}'

Dessa forma, você pode aplicar comandos diferentes a todos os arquivos.

Por exemplo, eu poderia remover todos os arquivos e diretórios que estão no dir1, mas não no dir2:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}' xargs -I {} rm -r {}
ND
fonte
9

No meu sistema linux para obter apenas os nomes de arquivos

diff -q /dir1 /dir2|cut -f2 -d' '
gerardw
fonte
7
Eu não coloco nomes de arquivos com espaços no meu sistema linux. ;)
gerardw 4/14
6
Eu não tive a intenção de imputar isso a você ... ;-p Assim como uma dica para alguém que faz ...
michuelnik
Nao funciona para mim. Minha estrutura de diretórios é como abaixoaudit-0.0.234/audit-data-warehouse-0.0.234/ audit-0.0.235/audit-data-warehouse-0.0.235/
Alex Raj Kaliamoorthy 4/17
diff -qrN /dir1 /dir2 | cut -f2 -d' 'funciona bem para mim!
Francesco
9

A abordagem da execução diff -qr old/ new/tem uma grande desvantagem: ela pode perder arquivos nos diretórios criados recentemente. Por exemplo, no exemplo abaixo, o arquivo data/pages/playground/playground.txtnão está na saída de diff -qr old/ new/enquanto o diretório data/pages/playground/está (procure playground.txt no seu navegador para comparar rapidamente). Também publiquei a seguinte solução no Unix e Linux Stack Exchange , mas vou copiá-la aqui também:

Para criar uma lista de arquivos novos ou modificados programaticamente, a melhor solução que eu poderia encontrar é usar rsync , sort e uniq :

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

Deixe-me explicar com este exemplo: queremos comparar dois lançamentos dokuwiki para ver quais arquivos foram alterados e quais foram criados recentemente.

Buscamos os alcatrões com o wget e os extraímos nos diretórios old/e new/:

wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1

A execução do rsync de uma maneira pode perder os arquivos recém-criados, como mostra a comparação do rsync e do diff aqui:

rsync -rcn --out-format="%n" old/ new/

produz a seguinte saída:

VERSION
doku.php
conf/mime.conf
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

A execução do rsync somente em uma direção perde os arquivos recém-criados e, ao contrário, os arquivos excluídos são comparados, compare a saída do diff:

diff -qr old/ new/

produz a seguinte saída:

Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ

Executar o rsync nos dois sentidos e classificar a saída para remover duplicatas revela que o diretório data/pages/playground/e o arquivo data/pages/playground/playground.txtforam perdidos inicialmente:

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

produz a seguinte saída:

VERSION
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

rsync é executado com estes argumentos:

  • -r "recursar em diretórios",
  • -c para comparar também arquivos de tamanho idêntico e apenas "pular com base na soma de verificação, não no tempo e tamanho da modificação",
  • -n para "executar uma avaliação sem alterações feitas" e
  • --out-format="%n" para "gerar atualizações usando o FORMAT especificado", que é "% n" aqui apenas para o nome do arquivo

A saída (lista de arquivos) de rsyncambas as direções é combinada e classificada usando sort, e essa lista classificada é então condensada removendo todas as duplicatas comuniq

iolsmit
fonte
Você não pode simplesmente executá-lo para trás ( diff new/ old/) para ver quais diretórios foram excluídos?
Jacques
A execução diff -qr new/ old/no exemplo acima com os dokuwiki tars produz a mesma saída que diff -qr old/ new/- ou seja, você vê que o diretório é novo / ausente, mas não os arquivos nele
iolsmit
-4
rsync -rvc --delete --size-only --dry-run source dir target dir
mayank
fonte