Concatenare più file CSV

Ultimamente ho avuto l’esigenza di unire tantissimi file di testo in formato .csv in modo da poterli riutilizzare altrove. Ogni file era composto da una riga di intestazione e dai dati a seguire. La mia esigenza era di unirli tutti assieme, mettendo un’unica intestazione con tutti i dati dopo di essa. Come si possono unire 622 file in questo modo con Linux?

La situazione

Supponiamo che stiamo lavorando col terminale dentro la directory job e che i file .csv siano in una sotto-directory chiamata dati:

job/
├── dati
│   ├── file-001.csv
│   ├── file-002.csv
│   ├── file-003.csv
│   ├── ...

Ogni file .csv è composto così:

LOCALITA;DATA;TMEDIA °C;TMIN °C;TMAX °C;...
Roma;1/5/2010;"17";"10";"22";...
Roma;2/5/2010;"17";"13";"21";...
Roma;3/5/2010;"18";"16";"21";...
...

La prima riga è l’intestazione, le successive i dati veri e propri. L’idea è quella di prelevare la riga di intestazione dal primo file e successivamente di prelevare tutte le righe da tutti i file, escludendo però la prima riga, che abbiamo già prelevato e che è identica in ogni file. Per il nostro scopo possiamo usare head e tail, in un unico comando.

Il comando

Il glorioso ed efficiente comando è:

head -n 1 dati/file-001.csv > unito.csv && tail -n+2 -q dati/*.csv >> unito.csv

Vediamolo nel dettaglio. Il comando è composto da due comandi distinti:

head ... && tail ...

Il primo comando (head -n 1) preleva dal primo file (ma potrebbe essere qualunque file, visto che tutti hanno la stessa intestazione dati) la riga di intestazione e la scrive nel file unito.csv dentro la directory job, esternamente quindi alla directory dati.

Il secondo (tail -n+2) preleva da tutti file .csv tutte le righe a partire dalla seconda e le accoda al file unito.csv. Il parametro -q dice a tail di non scrivere, prima di ogni blocco di testo accodato nel file unito.csv, la riga da cui ha prelevato il blocco stesso. Se togliessimo -q il risultato sarebbe qualcosa del tipo:

LOCALITA;DATA;TMEDIA °C;TMIN °C;TMAX °C;...
==> dati_meteo_roma/2010_05_Maggio_roma.csv <==
Roma;1/5/2010;"17";"10";"22";...
Roma;2/5/2010;"17";"13";"21";...
Roma;3/5/2010;"18";"16";"21";...
...
==> dati_meteo_roma/2010_06_Giugno_roma.csv <==
Roma;1/6/2010;"18";"13";"23";...
Roma;2/6/2010;"18";"15";"23";...
Roma;3/6/2010;"17";"11";"22";...
...

Con il parametro -q, invece, i dati saranno posti uno sotto l’altro:

LOCALITA;DATA;TMEDIA °C;TMIN °C;TMAX °C;...
Roma;1/5/2010;"17";"10";"22";...
Roma;2/5/2010;"17";"13";"21";...
Roma;3/5/2010;"18";"16";"21";...
...
Roma;30/5/2010;"22";"16";"27";...
Roma;31/5/2010;"20";"16";"25";...
Roma;1/6/2010;"18";"13";"23";...
Roma;2/6/2010;"18";"15";"23";...
Roma;3/6/2010;"17";"11";"22";...
...

Quanto tempo e lavoro sarebbe stato necessario se avessimo dovuto farlo manualmente?