Corso Linux / Confrontare file con diff e cmp: differenze e stati di uscita

Usa diff per vedere quali righe di testo sono cambiate e come, e cmp per verificare se due file sono identici byte per byte. Con GNU Diffutils, entrambi restituiscono lo stato di uscita 1 quando trovano differenze e 2 quando incontrano un problema durante il confronto. In questa lezione creerai due piccoli file e leggerai insieme l’output e lo stato di uscita.

Per preparare e controllare i file puoi consultare la lezione su come leggere il contenuto dei file. Lo stato 1 di diff indica una differenza rilevata: questa distinzione conta quando usi lo stato di uscita per l’esecuzione condizionale dei comandi (lezione in inglese).

Preparare due file da confrontare

L’esercizio usa Bash e GNU Diffutils. Esegui una riga alla volta in un terminale: se ~/linux-course-13-practice esiste già, scegli un nome nuovo e usa lo stesso nome in entrambi i comandi. Se mkdir o cd fallisce, fermati prima di creare i file. Le successive redirezioni > possono sovrascrivere file esistenti.

mkdir ~/linux-course-13-practice
cd ~/linux-course-13-practice
pwd

Controlla che pwd mostri la nuova directory di esercitazione dentro la tua home; un output di pwd da solo non prova che il precedente cd sia riuscito. Crea i due file soltanto nella directory appena preparata e senza riutilizzare file personali. Il contenuto differisce solo nella seconda riga: beta nel primo file e BETA nel secondo.

printf 'alpha\nbeta\ngamma\n' > old.txt
printf 'alpha\nBETA\ngamma\n' > new.txt

Puoi leggerli con cat old.txt e cat new.txt: entrambi devono avere tre righe, con alpha all’inizio e gamma alla fine. Se il contenuto è diverso da quello previsto, correggi prima i file di esercitazione.

Leggere le righe modificate con diff

diff confronta i file riga per riga. L’opzione -u seleziona il formato unificato, che include anche le righe invariate vicine alle modifiche; GNU Diffutils ne mostra tre per impostazione predefinita. Le due opzioni --label sostituiscono le normali intestazioni con nome del file e data di modifica, rendendo stabile l’esempio.

diff -u --label old --label new old.txt new.txt

Con i file appena creati, l’output è il seguente:

--- old
+++ new
@@ -1,3 +1,3 @@
 alpha
-beta
+BETA
 gamma

--- old identifica il primo file e +++ new il secondo. In @@ -1,3 +1,3 @@, ciascuna coppia indica la riga iniziale e il numero di righe del blocco: qui si parte dalla riga 1 e si considerano tre righe in entrambi i file. Il prefisso - segnala una riga rimossa dal primo contenuto, il prefisso + una riga presente nel secondo; lo spazio iniziale indica una riga invariata.

I prefissi di confronto non fanno parte del testo dei file. diff non determina quale file sia l’originale autentico: è l’ordine degli argomenti a fissare la direzione del confronto. Invertendo i due file, anche il significato di aggiunte e rimozioni si inverte.

Trovare la prima differenza di byte con cmp

cmp confronta i byte e, nell’uso predefinito, segnala la posizione della prima differenza. Dopo le cinque lettere ASCII di alpha e il carattere di fine riga, il primo byte della seconda riga occupa la posizione 7, contando da 1.

cmp old.txt new.txt

Con GNU cmp in un locale inglese puoi ottenere old.txt new.txt differ: byte 7, line 2. La dicitura dipende dalla versione e dall’ambiente: la build GNU Diffutils 3.12 inclusa in Git per Windows, usata per verificare questo esempio, mostra char 7, line 2. Il confronto resta basato sui byte, non sui caratteri Unicode visualizzati. In entrambi i casi la prima differenza dell’esempio è tra b e B nella seconda riga.

Il comando predefinito non elenca ogni differenza successiva; GNU cmp -l offre un output più dettagliato per i byte differenti. Per sapere soltanto se i file coincidono, usa invece -s e controlla immediatamente lo stato di uscita:

cmp -s old.txt new.txt
echo $?

Qui viene stampato 1, perché i file sono diversi. $? contiene lo stato del comando appena terminato: non inserire altri comandi tra cmp ed echo. Dopo echo, il nuovo valore di $? sarà quello di echo, non più quello del confronto. Anche senza output normale, uno stato diverso da zero richiede di distinguere differenza ed errore.

Distinguere una differenza da un errore

Stato Significato in GNU diff e cmp Che cosa controllare
0 Nessuna differenza rilevata Verifica che file e opzioni siano quelli previsti.
1 I file differiscono Leggi l’output di diff per capire le modifiche al testo.
2 Problema durante il confronto, per esempio un file non leggibile Controlla percorso, permessi e messaggio di errore.

Per osservare il caso 0 cambiando una sola condizione, conserva una copia di new.txt con cp new.txt saved-new.txt, purché questo terzo nome sia ancora libero nella directory di esercitazione. Poi esegui cp old.txt new.txt e ripeti separatamente i confronti: diff -u non deve mostrare cambiamenti, cmp -s non deve produrre output ed entrambi devono restituire 0. Leggi $? subito dopo ciascun confronto.

Ripristina quindi il solo file di esercitazione con cp saved-new.txt new.txt: i confronti devono tornare allo stato 1 e cat new.txt deve mostrare nuovamente BETA. Se una copia fallisce, fermati e controlla il messaggio prima di interpretare il confronto successivo. Questa prova sovrascrive intenzionalmente new.txt: non eseguirla su documenti personali.

Uno stato 1 è un risultato valido per questi strumenti, ma Bash lo tratta come stato non nullo nelle condizioni: un generico controllo di “successo o errore” può quindi confondere differenze ed errori operativi. La tabella descrive i comandi GNU avviati correttamente; errori della shell, come un comando non trovato, possono avere altri stati.

cmp è adatto all’identità esatta dei byte; diff -u aiuta a capire una modifica testuale. Terminatori di riga o codifiche differenti possono produrre differenze anche quando il testo sembra uguale. Per file binari, un diff testuale può essere poco informativo: parti da cmp se ti interessa l’identità. Opzioni che ignorano maiuscole o spazi cambiano il criterio di confronto, perciò “nessuna differenza” con tali opzioni non equivale necessariamente a identità byte per byte.

GNU diff -r può confrontare ricorsivamente alberi di directory, ma amplia l’insieme dei file letti: verifica prima entrambi i percorsi. Il normale confronto legge gli input e non applica automaticamente le modifiche mostrate nell’output.

Documentazione ufficiale

La descrizione GNU del formato unificato spiega intestazioni e prefissi. Le pagine di manuale di GNU diff e GNU cmp, distribuite da Debian, documentano opzioni e stati di uscita; il manuale di Bash sugli stati di uscita chiarisce l’interpretazione della shell.