Impedisci a diff di controllare la presenza di newline alla fine del file


21

Ho due grandi alberi, che voglio confrontare. Alcuni dei file nella struttura sono diversi solo perché uno ha una nuova riga alla fine e l'altro file manca di questa nuova riga. Voglio ignorare questo fatto. Ho provato a chiamare in diffquesto modo:

diff --ignore-all-space -r <dir1> <dir2>

E questo sta funzionando. Il mio problema è che ignora anche altre differenze (legate allo spazio), che possono essere importanti.

In sintesi: voglio solo ignorare la nuova riga di EOF. È possibile con diff?

Risposte:


17

Fondamentalmente è necessario confrontare due file, ignorando in modo condizionale il byte finale. Non esiste un'opzione 'diff' per farlo - ma ci sono un certo numero di modi in cui potrebbe essere fatto (ad esempio, viene in mente anche hex diff.)

Per usare 'diff', sostanzialmente devi modificare i file che mancano alla nuova riga alla fine di un file, e poi confrontare. È possibile creare una directory temporanea con i file modificati o con un po 'di scripting potrebbe essere eseguita in memoria. (Quanto a quale è preferito dipende dalla preferenza, dimensione del file, numero di file ...)

Ad esempio, quanto segue modificherà il contenuto di un file (usare sed -iper modificare sul posto, questo stampa solo su stdout) per aggiungere una nuova riga se manca (o lasciare invariato il file se esiste già una nuova riga):

sed -e '$a\'  file1.txt

E solo per rivedere la sintassi 'diff' (restituire vero significa che sono uguali, falso significa diverso):

$ diff a/file1.txt   b/file1.txt  \
      && echo '** are same' || echo '** are different'
2c2
< eof
---
> eof
\ No newline at end of file
** are different

Verifica che solo gli spazi siano diversi:

$ diff --ignore-all-space  a/file1.txt   b/file1.txt \
     && echo '** are same' || echo '** are different'
** are same

In bash, possiamo usare 'sed' per manipolare il contenuto del file mentre viene passato a 'diff' (file originali lasciati invariati):

$ diff <(sed -e '$a\' a/file1.txt) <(sed -e '$a\' b/file1.txt) \
     && echo '** are same' || echo '** are different'
** are same

Ora tutto ciò che devi fare è emulare diff -rper confrontare ricorsivamente le directory. Se si confrontano le directory ae b, quindi, per tutti i file in a(ad es. a/dir1/dir2/file.txt) Derivano il percorso del file in b(ad es. b/dir1/dir2/file.txt) E si confrontano:

$ for f in $( find a -type f  )
> do
>    diff <(sed -e '$a\' $f) <(sed -e '$a\' b/${f#*/})
> done

Una versione leggermente più dettagliata:

$ for f in $( find a -type f  )
> do
>   f1=$f
>   f2=b/${f#*/}
>   echo "compare: $f1 $f2"
>   diff <(sed -e '$a\' $f1) <(sed -e '$a\' $f2) \
>       && echo '** are same' || echo '** are different'
> done && echo '** all are same' || echo '** all are different'
compare: a/file1.txt b/file1.txt
** are same
compare: a/file2.txt b/file2.txt
** are same
** all are same

potresti spiegare cosa sed -e '$a\'fa esattamente? thx
törzsmókus

eseguire sed, dato il seguente ( -e) script / espressione, che corrisponde alla fine del file ( $), ed eseguire l'azione "append" (a \), ma in realtà non specificare alcun testo (niente dopo il `\`) che aggiungerà ancora un EOF / newline alla fine del file (solo se manca).
michael,

grazie. Non ho visto a\ ancora.
törzsmókus,

1

Ho risolto il problema aggiungendo una nuova riga a ciascuno dei file e ignorando le righe vuote nel diff (opzione -B). Queste soluzioni potrebbero non essere adatte al tuo caso d'uso ma potrebbero aiutare gli altri:

echo >> $FILE1 
echo >> $FILE2
diff -B $FILE1 FILE2 

0

Inoltra l'output di diffun grepcomando che rilascia il messaggio che non vuoi vedere.


non bene. diff -r esiste con risultato! = 0 se non aggiungo --ignore-all-space. Per essere chiari: voglio che il diff ignori le nuove righe di EOF e solo di EOF. E voglio che riporti un risultato che soddisfi questi criteri. Cioè, se i file nella struttura differiscono solo sulla nuova riga in EOF, ciò non deve essere considerato una differenza, e quindi diff deve restituire 0.
dangonfast

0

Ho solo pensato a un approccio diverso, che funzionerà per file più grandi (e non copia ancora o modifica i file originali). Dovresti comunque emulare l'attraversamento ricorsivo della directory (e ci sono molti modi per farlo), ma questo esempio non usa 'sed', ma piuttosto confronta due file, escludendo l'ultimo byte, usando cmp, ad esempio,

$ cmp  a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
cmp: EOF on b/file1.txt
** are different

$ du -b a/file1.txt  b/file1.txt 
13  a/file1.txt
12  b/file1.txt

$ cmp  -n 12 a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
** are same

Continuare a scorrere su tutti i file nella directory e per due file a / file.txt e b / file.txt, calcolare la dimensione del file più grande e sottrarre uno, quindi eseguire un diff binario ( cmp) usando questo numero di byte (anche in bash):

(( bytes = $(du -b a/file.txt  b/file.txt  | sort -nr | head -1  | cut -f1) - 1 ))
cmp -n $bytes a/file.txt b/file.txt

Il ciclo sui file sarebbe lo stesso dell'altra risposta usando sede diff.


0

La risposta è semplice
Il messaggio sulla newline mancante non si trova nel flusso di output diffma nel flusso di errori. Quindi piegalo al nirvana e hai finito per sempre

diff -rqEeB fileA fileB 2> /dev/null

diff restituisce un valore! = 0 se trova differenze e voglio verificare quel valore. Il reindirizzamento a / dev / null non fa dimenticare a diff la differenza, quindi il valore restituito è! = 0, che non desidero. Voglio che il diff consideri due file uguali se l'unica differenza è l'ultima newline
dangonfast,

-1

C'è una bandiera in comune: --strip-trailing-crfa esattamente quello che hai chiesto


-1. Hai provato questo? Tratta /r/ncome/n e non ha nulla a che fare con extra /nappena prima di EOF.
Kamil Maciorowski,

Ho provato questo e l'ho usato per diff file con diversi dos / unix newline ... non è corretto?
Dharman,

La domanda riguarda l'ignorare la nuova riga solo su EOF (fine del file).
Kamil Maciorowski il
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.