Comando diff in Linux: confrontare file e directory e leggere le differenze
Il comando diff confronta due file di testo e mostra le righe da cambiare per passare dal primo al secondo. Con -u produce un confronto unificato con righe di contesto; con -r confronta anche le sottodirectory, per controllare sorgenti e configurazioni.
Gli esempi si riferiscono a GNU diff, parte di GNU Diffutils, eseguito da una shell come Bash. Controlla diff --version, diff --help e man diff sul sistema: le opzioni lunghe e il colore possono variare tra implementazioni. Il confronto legge i file; scritture e creazione di cartelle negli esempi servono solo a preparare la prova o salvare una patch.
Che cos'è il comando diff?
Diff confronta il contenuto riga per riga, non il significato del programma o della configurazione. In GNU diff lo stato di uscita 0 indica nessuna differenza secondo le opzioni scelte, 1 indica differenze e 2 un problema, come un file non leggibile. Un output vuoto va quindi interpretato insieme allo stato e agli eventuali messaggi di errore.
Sintassi di base
diff [OPTION]... FILE1 FILE2
diff [OPTION]... DIRECTORY1 DIRECTORY2
OPTION, FILE1 e gli altri nomi sono segnaposto. Sostituiscili con percorsi esistenti, racchiudendo tra virgolette quelli con spazi; diff -u -- "vecchio file.conf" "nuovo file.conf" separa le opzioni dai nomi. Un singolo trattino come input indica lo standard input. Quando entrambi gli argomenti sono directory, diff confronta i nomi corrispondenti e segnala quelli presenti da un solo lato.
Utilizzo base di diff
Confrontare due file
Il formato predefinito usa la notazione tradizionale: per esempio 1c1 indica la sostituzione della riga 1 del primo file con la riga 1 del secondo; < precede il contenuto vecchio e > quello nuovo. Le lettere a e d indicano aggiunte e rimozioni. Il comando seguente richiede due copie di configurazione già esistenti e non le modifica.
diff old.conf new.conf
Produrre un confronto unificato
-u mostra le righe cambiate insieme, per impostazione predefinita, a tre righe di contesto. Se il file è corto o la modifica è vicina a un bordo, il contesto è minore. Puoi scegliere un altro numero con -U 5. Invertendo gli argomenti si inverte la direzione del confronto.
diff -u old.conf new.conf
Confrontare directory ricorsivamente
-r scende nelle sottodirectory con nomi corrispondenti; -u conserva il formato unificato per i file di testo. Sostituisci i due percorsi con alberi esistenti. I messaggi sui nomi presenti da un solo lato non costituiscono da soli una patch completa: GNU -N tratta i file assenti come vuoti quando questo è il comportamento desiderato. Un confronto non verifica proprietari, permessi o tutti i metadati e non sostituisce un backup. Se i collegamenti simbolici devono essere confrontati come collegamenti, valuta l’opzione GNU --no-dereference.
diff -ru project-old project-new
Leggere il formato unificato e lo stato di uscita
La prova seguente crea before.txt e after.txt in una cartella nuova. Esegui l’intero blocco: se diff-demo esiste già, si ferma senza sovrascriverne i file; scegli un nome diverso per ripetere la prova. Le parentesi mantengono locale il cambio di directory. Le etichette GNU --label rendono stabile l’intestazione, senza date.
(
mkdir diff-demo || exit 1
cd diff-demo || exit 1
printf 'old\n' > before.txt || exit 1
printf 'new\n' > after.txt || exit 1
stato=0
diff -u --label before.txt --label after.txt before.txt after.txt || stato=$?
printf 'Stato: %s\n' "$stato"
case "$stato" in 0|1) ;; *) exit "$stato" ;; esac
)
Output completo del confronto dimostrativo, prima della riga finale Stato: 1:
--- before.txt
+++ after.txt
@@ -1 +1 @@
-old
+new
Le intestazioni --- e +++ identificano rispettivamente il primo e il secondo input. @@ -1 +1 @@ indica un blocco di modifica, detto hunk, che riguarda una riga a partire dalla riga 1 su ciascun lato; in blocchi più lunghi può comparire inizio,numero. Nelle righe del blocco, - indica una rimozione dal primo file, + un’aggiunta nel secondo e uno spazio iniziale una riga di contesto. Lo stato 1 conferma la differenza; non è un guasto del comando.
Opzioni principali
| Opzione | Scopo |
|---|---|
-u |
Mostra il formato unificato con tre righe di contesto predefinite; -U NUM sceglie il numero. |
-r, --recursive |
Scende nelle sottodirectory corrispondenti. |
-q, --brief |
Segnala le differenze senza stampare le righe cambiate; mantiene gli stati 0, 1 e 2. |
-s |
Segnala anche quando i file sono identici. |
-w |
Ignora le differenze di spazi bianchi dentro le righe, anche tra zero e uno spazio; non elimina i confini delle righe. |
-b |
Ignora le differenze nella quantità di spazi bianchi e quelli finali; uno spazio interno e la sua assenza restano diversi. |
-i |
Ignora differenze tra maiuscole e minuscole nel contenuto; non equivale a ignorarle nei nomi dei file. |
--color=auto |
Colora l’output quando GNU diff lo invia a un terminale; --color=never evita sequenze di colore. |
Esempi pratici
Creare un file patch
Questo esempio autonomo crea due piccole configurazioni e salva la differenza in una cartella nuova, diff-patch-demo. La modalità set -C impedisce di troncare un file di output già esistente. Lo stato viene acquisito senza trattare 1 come errore; se è 2, non usare il file prodotto come patch valida. Le etichette indicano una modifica al solo app.conf, e --color=never mantiene il file privo di codici colore.
Prima di applicare una patch reale, controlla intestazioni, contenuto e directory di destinazione, e conserva una copia o una revisione recuperabile. Dopo aver eseguito il blocco, entra nella cartella con cd diff-patch-demo. Crea la copia di prova con (set -C; cat original.conf > app.conf), che si ferma se app.conf esiste già; poi usa patch --dry-run -p0 < config.patch: controlla l’applicabilità senza cambiare il file. Solo dopo il controllo, patch -p0 < config.patch applica la modifica. Qui -p0 conserva il nome app.conf; una patch con prefissi di directory richiede una scelta diversa di -p. Diff genera il testo della patch, mentre patch modifica i file.
(
mkdir diff-patch-demo || exit 1
cd diff-patch-demo || exit 1
set -C
printf 'port=8080\n' > original.conf || exit 1
printf 'port=9090\n' > modified.conf || exit 1
stato=0
diff -u --color=never --label app.conf --label app.conf \
original.conf modified.conf > config.patch || stato=$?
case "$stato" in
0) printf 'Nessuna differenza; patch vuota.\n' ;;
1) printf 'Patch creata: diff-patch-demo/config.patch\n' ;;
*) printf 'Errore diff: %s\n' "$stato" >&2; exit "$stato" ;;
esac
)
Riassumere le differenze tra directory
-qr confronta due directory esistenti e segnala file differenti e nomi presenti da un solo lato, senza mostrare ogni riga cambiata. Per provarlo, prepara due cartelle con un file omonimo dal contenuto diverso e un file presente solo nella prima: vedrai entrambi i casi. L’output è destinato alla lettura, non è un elenco di nomi delimitati in modo sicuro per una successiva cancellazione.
diff -qr release-a release-b
Ignorare cambiamenti nella quantità di spazi
Il comando seguente presuppone due file già esistenti. Confrontando le lettere a e b separate da due spazi con le stesse lettere separate da uno spazio, -b non segnala differenze; confrontando ab con a b, invece, le segnala. -w ignora anche quest’ultima differenza. Queste opzioni possono nascondere modifiche importanti nell’indentazione, nelle stringhe o nei dati: usa prima un confronto ordinario quando gli spazi hanno significato.
diff -u -b before.txt after.txt
diff e comandi correlati
| Comando | Ruolo principale | Quando usarlo |
|---|---|---|
diff |
Confronto del testo riga per riga | Sorgenti, configurazioni e alberi di directory |
cmp |
Confronto byte per byte, con segnalazione della prima differenza | Verificare l’uguaglianza esatta o il primo byte diverso |
git diff |
Confronto integrato con Git | Modifiche nella directory di lavoro e tra revisioni |
comm |
Confronto di righe già ordinate con lo stesso criterio | Separare righe comuni e presenti in un solo input; considerare gli eventuali duplicati |
Avvertenze importanti
Lo stato di uscita 1 significa diverso
Negli script acquisisci subito lo stato, come negli esempi completi, e distingui 0, 1 e 2. Con set -e, un semplice diff che trova differenze può interrompere lo script: la forma stato=0; diff ... || stato=$? conserva il risultato per gestirlo esplicitamente. Evita diff ... || true se hai bisogno di distinguere una differenza da un errore di lettura.
Scegliere lo strumento adatto ai file binari
Per file riconosciuti come binari, diff normalmente segnala soltanto se differiscono. Per verificare esattamente i byte usa cmp; diff -a forza il trattamento come testo ma non rende una differenza binaria una patch testuale affidabile. Controlla inoltre codifica e terminatori di riga: in GNU diff --strip-trailing-cr ignora un ritorno a capo CR alla fine di ogni riga, se questa normalizzazione è appropriata.
Le opzioni di spaziatura possono nascondere cambiamenti significativi
Spazi e tabulazioni possono cambiare il significato del testo; ignorarli è un filtro di confronto, non una correzione del file. La diversa disposizione delle righe resta significativa anche con -w. Un messaggio che segnala l’assenza del carattere di fine riga finale riguarda una differenza reale nella terminazione del file e va letto insieme al resto del confronto.
FAQ
Che cosa significa un output vuoto di diff?
Con stato 0 non ci sono differenze secondo le opzioni scelte. Un filtro come -w può nascondere differenze nei byte; con stato 2 controlla gli errori sullo standard error, anche se lo standard output è vuoto.
Quale formato di output è più facile da leggere?
Il formato unificato di diff -u raggruppa modifiche e contesto. Le intestazioni distinguono i file, mentre i prefissi meno e più distinguono rimozioni e aggiunte.
Diff può confrontare intere directory?
Sì: -r visita le sottodirectory corrispondenti e -q limita il dettaglio. Non è un confronto completo di tutti i metadati; verifica separatamente la gestione dei file presenti da un solo lato e dei collegamenti simbolici.
Il codice di uscita 1 è un errore?
Per GNU diff, 1 significa che il confronto ha trovato differenze; 0 significa nessuna differenza secondo le opzioni e 2 indica un problema. Gli script devono gestire separatamente questi risultati.




