Compare recursivamente dois diretórios com diff -r sem saída em links quebrados


38

Estou usando diff -r a bpara comparar recursivamente os diretórios a e b . Muitas vezes acontece que embora existem alguns links quebrados (os mesmos links quebrados em ambas a e b diretórios e apontando para os mesmos, alvos não-existentes).

diff então envia mensagens de erro para esses casos e sai com um código de saída diferente de zero, no entanto, gostaria que ele permanecesse silencioso e saia com 0, pois os diretórios são iguais no meu livro.

Como eu posso fazer isso?


Você ainda deseja que os links simbólicos sejam comparados (e identificados como equivalentes, mas quebrados), ou é aceitável ignorar todos os links simbólicos ao fazer essa comparação?
ire_and_curses

comparado e identificado como equivalente, não me importo se estiverem quebrados. Estou apenas tentando verificar se meu rsync funcionou.
Marcus Junius Brutus

Respostas:


24

Para a versão 3.3 ou posterior diff, você deve usar a --no-dereferenceopção, conforme descrito na resposta de Pete Harlan .

Infelizmente, versões mais antigas diff do não suportam ignorar links simbólicos :

Alguns arquivos não são diretórios nem arquivos regulares: são arquivos incomuns, como links simbólicos, arquivos especiais de dispositivos, pipes nomeados e soquetes. Atualmente, difftrata links simbólicos como arquivos regulares; trata outros arquivos especiais, como arquivos regulares, se forem especificados no nível superior, mas simplesmente relata sua presença ao comparar diretórios. Isso significa que patchnão pode representar alterações nesses arquivos. Por exemplo, se você alterar para qual arquivo um link simbólico aponta, diffgera a diferença entre os dois arquivos, em vez da alteração no link simbólico.

diffopcionalmente, deve relatar alterações em arquivos especiais e patchdeve ser estendido para entender essas extensões.

Se tudo o que você deseja é verificar um rsync (e presumivelmente corrigir o que está faltando), execute o comando rsync pela segunda vez. Se você não quiser fazer isso, a soma do diretório pode ser suficiente.

Se você realmente deseja fazer isso diff, pode findpular os links simbólicos e executar o diff em cada arquivo individualmente. Passe seus diretórios a e b em como argumentos:

#!/bin/bash
# Skip files in $1 which are symlinks
for f in `find $1/* ! -type l`
do
    # Suppress details of differences
    diff -rq $f $2/${f##*/}
done

ou como uma linha:

for f in `find a/* ! -type l`;do diff -rq $f b/${f##*/};done

Isso identificará arquivos que diferem em conteúdo ou arquivos que estão em a, mas não em b .

Observe que:

  • como estamos pulando links simbólicos por inteiro, isso não notará se os nomes dos links simbólicos não estiverem presentes em b . Se você exigisse isso, seria necessário um segundo passe de localização para identificar todos os links simbólicos e, em seguida, verificar explicitamente a existência deles em b .
  • Arquivos extras em b não serão identificados, pois a lista é construída a partir do conteúdo de a . Isso provavelmente não é um problema para o seu rsynccenário.

O script proposto não funciona recursivamente para nenhum diretório presente no diretório 'a' (os caminhos criados para 'b' usando b / $ {f ## *} não estão corretos).
Marcus Junius Brutus

@MarcusJuniusBrutus - Sim, você está certo. Eu acho que a solução é remover um #, por exemplo, for f in encontre um / *! tipo l ;do echo $f b/${f#*/};done. Eu não tenho tempo para testar isso agora. Deixe-me saber se isso funciona.
precisa saber é o seguinte

Ele é melhor no entanto, ainda mexe-se os caminhos de arquivos em muitos casos. O script (com um # removido) parece precisar ser chamado de um diretório diretamente sobre 'a' para funcionar.
Marcus Junius Brutus

Essa resposta torna-se obsoleto quando se usa GNU diff 3.3 (ver postagens abaixo)
Bernd Gloss

O script acima tem vários problemas, devido à localização de todos os nomes de arquivos e alimentá-los em uma linha de comando expandida. (1) Ele funcionará apenas com pequenas coleções de arquivos desde então. (2) Qualquer nome de arquivo com caractere especial (mesmo um espaço) não será processado. (3) Sempre use em $(xxx)vez de backticks. A simetria dos backticks os torna menos legíveis e evita o aninhamento. Em relação a 1 e 2, consulte stackoverflow.com/questions/11366184/…
Stéphane Gourichon

19

Desde a versão 3.3, o GNU diffnão suporta a remoção de links simbólicos, mas compara os caminhos para os quais eles apontam.

Instale o GNU diffutils> = 3.3 e use a --no-dereferenceopção; não existe uma opção curta para isso.

O diagnóstico será silencioso se for igual ou:

Links simbólicos /tmp/noderef/a/symlinke /tmp/noderef/b/symlinkdiferentes


Agora, se ao menos ele mostrasse as alterações no conteúdo, como se o link simbólico fosse um arquivo comum ...: - /
lindes

6

Você pode usar uma versão mais recente do diff

O diffno GNU diffutils3.3 inclui uma --no-dereferenceopção que permite comparar os links simbólicos em si e não em seus destinos. Relata se eles diferem, fica quieto se eles concordam e não se importa se estão quebrados.

Não sei quando a opção foi adicionada; não está presente no 2.8.1.


Eu posso confirmar é não existe no diff (diffutils GNU) 3.2 quer
Elder Geek
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.