Confrontare ricorsivamente due directory con diff -r senza output su collegamenti interrotti


38

Sto usando diff -r a bper confrontare ricorsivamente le directory a e b . Accade spesso però che ci sono alcuni link non funzionanti (gli stessi collegamenti interrotti sia una e B directory e indicando gli stessi, non esistenti target).

diff quindi genera messaggi di errore per quei casi ed esce con un codice di uscita diverso da zero, tuttavia vorrei che rimanesse silenzioso e uscisse con 0 poiché le directory sono le stesse nel mio libro.

Come lo posso fare?


Vuoi ancora confrontare i link simbolici (e identificati come equivalenti ma non funzionanti) o è accettabile ignorare tutti i link simbolici quando si fa questa diff?
ire_and_curses,

confrontato e identificato come equivalente, non mi importa se sono rotti. Sto solo cercando di verificare che il mio rsync abbia funzionato.
Marco Junius Bruto

Risposte:


24

Per la versione 3.3 o successive diff, dovresti usare l' --no-dereferenceopzione, come descritto nella risposta di Pete Harlan .

Sfortunatamente, le versioni precedenti di diff non supportano l'ignoranza dei symlink :

Alcuni file non sono né directory né file normali: sono file insoliti come collegamenti simbolici, file speciali di dispositivi, named pipe e socket. Attualmente, difftratta i collegamenti simbolici come file normali; tratta altri file speciali come i file normali se sono specificati al livello superiore, ma segnala semplicemente la loro presenza quando si confrontano le directory. Ciò significa che patchnon è possibile rappresentare modifiche a tali file. Ad esempio, se si modifica il file a cui punta un collegamento simbolico, viene diffemessa la differenza tra i due file, anziché la modifica al collegamento simbolico.

diffdovrebbe facoltativamente segnalare le modifiche a file speciali appositamente e patchdovrebbe essere esteso per comprendere queste estensioni.

Se tutto ciò che vuoi è verificare un rsync (e presumibilmente correggere ciò che manca), allora potresti semplicemente eseguire il comando rsync una seconda volta. Se non si desidera farlo, potrebbe essere sufficiente fare un check-summing della directory .

Se vuoi davvero farlo diff, allora puoi usare findper saltare i collegamenti simbolici ed eseguire diff su ogni file individualmente. Passa le tue directory a e b come argomenti:

#!/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

o come one-liner:

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

Ciò identificherà i file che differiscono nel contenuto o i file che si trovano in a ma non in b .

Nota che:

  • poiché stiamo saltando del tutto i collegamenti simbolici, ciò non si noterà se i nomi dei collegamenti simbolici non sono presenti in b . Se richiesto, è necessario un secondo passaggio di ricerca per identificare tutti i collegamenti simbolici e quindi verificare esplicitamente la loro esistenza in b .
  • I file extra in b non verranno identificati, poiché l'elenco è costruito dal contenuto di a . Questo probabilmente non è un problema per il tuo rsyncscenario.

Lo script proposto non funziona in modo ricorsivo per nessuna directory presente nella directory 'a' (i percorsi creati per 'b' usando b / $ {f ## *} non sono corretti).
Marco Giunio Bruto,

@MarcusJuniusBrutus - Sì, hai ragione. Penso che la soluzione sia rimuovere un #, ad esempio for f in trovare un / *! tipo l ;do echo $f b/${f#*/};done. Non ho tempo di provarlo adesso. Fammi sapere se funziona.
ire_and_curses,

Si è meglio tuttavia scombina ancora i filepaths in molti casi. Per funzionare, sembra che lo script (con un # rimosso) debba essere richiamato da una directory direttamente su 'a'.
Marco Giunio Bruto,

Questa risposta diventa obsoleta quando si utilizza GNU diff 3.3 (vedere le pubblicazioni seguenti)
Bernd Gloss

Lo script sopra ha diversi problemi, dovuti innanzitutto alla ricerca di tutti i nomi dei file e alla loro alimentazione in una riga di comando estesa. (1) Funzionerà solo con piccole raccolte di file da allora. (2) Qualsiasi nome di file con carattere speciale (anche uno spazio) non verrà elaborato. (3) Utilizzare sempre al $(xxx)posto dei backtick. La simmetria dei backtick li rende meno leggibili e impedisce l'annidamento. Per quanto riguarda 1 e 2 vedi stackoverflow.com/questions/11366184/...
Stéphane Gourichon

19

Poiché la versione 3.3 GNU diffsupporta il non dereferenziamento dei collegamenti simbolici, ma confronta i percorsi a cui puntano.

Installa GNU diffutils> = 3.3 e usa l' --no-dereferenceopzione; non esiste un'opzione breve per quello.

La diagnostica sarà silenziosa se uguale o:

I collegamenti simbolici /tmp/noderef/a/symlinke /tmp/noderef/b/symlinkdifferiscono


Ora, se solo mostrasse le modifiche al contenuto, come se il collegamento simbolico fosse un file normale ...: - /
lindes

6

È possibile utilizzare una versione più recente di diff

In diffGNU diffutils3.3 include --no-dereferenceun'opzione che ti consente di confrontare i link simbolici stessi anziché i loro target. Segnala se differiscono, è tranquillo se sono d'accordo e non gli importa se sono rotti.

Non so quando è stata aggiunta l'opzione; non è presente in 2.8.1.


Posso confermare che non esiste in diff (GNU diffutils) 3.2
Elder Geek
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.