Comando join in Linux: unire file per chiave e controllare le righe mancanti
join combina le righe di due file di testo quando il campo chiave ha lo stesso valore. Si distingue da paste, che affianca le righe per posizione, perché cerca la corrispondenza fra i valori dei campi.
Per impostazione predefinita usa il primo campo di ciascun file e mostra soltanto le righe abbinate. Entrambi gli input devono essere ordinati secondo la chiave e le stesse regole di confronto. Le opzioni -a e -v permettono di includere o isolare le righe senza corrispondenza.
Sintassi di base
join [OPTION]... FILE1 FILE2
Questa è una notazione: sostituisci i segnaposto con opzioni e percorsi reali, senza scrivere le parentesi quadre. I campi si contano da 1. Senza -t, spazi e tabulazioni separano i campi, le sequenze di separatori contano come uno e quelli iniziali vengono ignorati. L’output predefinito contiene la chiave, gli altri campi del primo file e poi quelli del secondo, separati da spazi.
Puoi usare - al posto di uno dei due file per leggere dallo standard input; non usarlo per entrambi. Le opzioni GNU, fra cui --check-order usata qui sotto, possono non esistere in altre implementazioni: verifica man join nel sistema in uso.
Preparare, ordinare, unire e controllare le righe mancanti
Esegui il blocco completo in una shell compatibile con Bash, con GNU sort e GNU join disponibili. Crea tutti gli input in una nuova directory temporanea ed esegue il lavoro in una subshell, indicata dalle parentesi tonde. Non sovrascrive file nella directory di partenza e non cambia la directory della shell chiamante. L’ultima riga indica dove sono rimasti i dati di prova: esaminali e, quando non servono più, rimuovi soltanto quelli.
(
set -eu
labdir=$(mktemp -d)
cd "$labdir"
printf 'b Bob
a Ana
c Cat
' > names.txt
printf 'a 7
b 12
' > scores.txt
LC_ALL=C sort -k1,1 names.txt > names.sorted
LC_ALL=C sort -k1,1 scores.txt > scores.sorted
LC_ALL=C join --check-order names.sorted scores.sorted
LC_ALL=C join --check-order -a 1 names.sorted scores.sorted
printf 'a:Ana
b:Bob
' > users.txt
printf 'a:reader
b:writer
' > roles.txt
LC_ALL=C sort -t ':' -k1,1 users.txt > users.sorted
LC_ALL=C sort -t ':' -k1,1 roles.txt > roles.sorted
LC_ALL=C join --check-order -t ':' users.sorted roles.sorted
printf 'Lab files: %s\n' "$labdir"
)
La prima esecuzione di join produce a Ana 7 e b Bob 12. L’esecuzione con -a 1 ripete queste due righe e aggiunge c Cat, che non ha un punteggio. L’esempio con i due punti produce a:Ana:reader e b:Bob:writer. Infine compare Lab files: seguito dal percorso temporaneo, che cambia a ogni esecuzione.
Per ulteriori prove apri una nuova shell o spostati nella directory mostrata, usando cd seguito dal percorso fra virgolette. Da lì LC_ALL=C join --check-order -v 1 names.sorted scores.sorted mostra soltanto c Cat; con -v 2 non esce alcuna riga, perché tutti i punteggi hanno un nome corrispondente.
Nel laboratorio le chiavi sono semplici lettere ASCII senza spazi iniziali: sort -k1,1 è sufficiente per questi dati. Per la separazione predefinita di join, la preparazione generale consigliata da GNU è LC_ALL=C sort -k1b,1 input.txt > input.sorted, scegliendo una destinazione nuova. Il modificatore b ignora i separatori iniziali della chiave. Per campi diversi o un delimitatore esplicito, adatta anche la chiave di sort: non limitarti a ordinare l’intera riga.
L’esempio con -t ':' usa lo stesso delimitatore anche in sort. Il confronto delle chiavi è testuale: valori come 10 e 2 non richiedono un ordinamento numerico per join. Mantieni lo stesso LC_ALL=C nelle due fasi; altri ambienti locali possono definire confronti diversi. La guida a sort spiega come selezionare il campo da ordinare.
Opzioni per chiavi, righe mancanti e output
| Opzione | Uso |
|---|---|
-t carattere |
Imposta il separatore dei campi sia in ingresso sia in uscita. Ogni sua occorrenza è significativa. |
-1 N / -2 N |
Sceglie il campo chiave del primo e del secondo file, con indici a partire da 1. |
-a 1 / -a 2 |
Include anche le righe non abbinabili del file indicato, oltre alle coppie corrispondenti. |
-v 1 / -v 2 |
Mostra soltanto le righe non abbinabili del file indicato, escludendo le coppie corrispondenti. |
-o formato |
Seleziona i campi di output e il loro ordine. Usa 0 per la chiave o 1.N e 2.N per i campi dei due file. |
Per esempio, sui file del laboratorio LC_ALL=C join --check-order -a 1 -e 'NA' -o '0,1.2,2.2' names.sorted scores.sorted produce a Ana 7, b Bob 12 e c Cat NA, su tre righe. Qui -e riempie il campo mancante selezionato da -o. Il formato va passato come un solo argomento; 0 mantiene la chiave anche nelle righe non abbinate.
Se la chiave è nel secondo campo del primo file e nel primo del secondo, usa -1 2 -2 1 e prepara i due input rispettivamente con la chiave di ordinamento -k2b,2 e -k1b,1 nella modalità a spazi. Con -t ':', usa anche in sort -t ':' e seleziona i campi corrispondenti senza introdurre una regola diversa sugli spazi.
Precauzioni: ordinamento, duplicati e salvataggio
Non trattare l’output di un comando fallito come un risultato completo. GNU --check-order controlla l’ordinamento anche quando tutte le righe sarebbero abbinabili; può però avere già emesso alcune righe prima di trovare il problema. Controlla il codice di uscita e i messaggi d’errore, correggi gli input e ripeti l’operazione. Senza quell’opzione, l’assenza di un avviso non dimostra in generale che l’ordinamento sia corretto.
Le chiavi duplicate possono moltiplicare il numero di righe: se una chiave compare due volte in un file e tre nell’altro, join produce sei combinazioni per quella chiave. Controlla i duplicati e il numero dei risultati prima di presumere una relazione uno a uno. Non eliminare duplicati indiscriminatamente se ogni riga rappresenta un record distinto.
Con -t ',' join non interpreta le virgolette di un CSV: una virgola dentro un valore tra virgolette resta un separatore per il comando. Per dati CSV con queste caratteristiche usa strumenti che ne comprendano il formato. Le intestazioni richiedono una gestione separata; l’estensione GNU --header tratta le prime righe come intestazioni e non va applicata a file che iniziano subito con dati.
Per conservare il risultato del laboratorio puoi usare LC_ALL=C join --check-order names.sorted scores.sorted > joined.txt, scegliendo un nome nuovo e verificando poi cat joined.txt e il successo del comando. La redirezione può sovrascrivere una destinazione esistente. Non indicare mai uno degli input come destinazione: la shell può svuotarlo prima della lettura. Nel laboratorio gli originali names.txt e scores.txt restano invariati e le copie ordinate hanno nomi distinti.
Domande frequenti
Posso usare join direttamente su file non ordinati?
Per il normale uso di join prepara copie ordinate secondo i campi chiave, i delimitatori e le stesse impostazioni locali del comando. Un risultato apparentemente corretto su dati non ordinati non garantisce che tutti gli abbinamenti siano stati trovati. Con GNU puoi aggiungere --check-order e verificare anche il codice di uscita.
Documentazione di riferimento
La pagina di manuale GNU di join su man7 descrive le opzioni della versione documentata. Il riferimento POSIX per join chiarisce il formato dei campi, i requisiti di ordinamento e le combinazioni prodotte dalle chiavi duplicate.




