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?

Marcus Junius Brutus
fonte
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.
ire_and_curses
fonte
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

Philippe De Muyter
fonte
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.

Pete Harlan
fonte
Eu posso confirmar é não existe no diff (diffutils GNU) 3.2 quer
Elder Geek