Capita spesso di dover analizzare, modificare e processare rapidamente grandi quantità di file, sia per numero che per dimensioni. Spesso, però, si tratta di file di testo in formato CSV (Comma Separated Values). Aprirli con applicazioni foglio di calcolo come Excel, LibreOffice o OpenOffice sovraccarica la memoria della macchina. Inoltre, elaborare un gran numero di file in un unico batch spesso fallisce dopo qualche ora a causa di qualche anomalia imprevista in uno dei file.
Finisci inevitabilmente per passare molto tempo tra schermate bloccate, riavvii e lunghe attese.
Eppure, la maggior parte di queste operazioni può essere svolta con poche righe di codice. Ancora meglio, un po' di dimestichezza con alcune semplici righe di comando della shell può farti risparmiare tempo e ridurre la frustrazione.
Questo post offre una panoramica di alcuni comandi della shell che uso quasi ogni giorno. Spero ti siano utili.
Note rapide
Nota che esistono diversi tipi di shell (bash, zsh, ...), con bash la più comune poiché è la shell predefinita su OS X e sulle principali distribuzioni linux. Zsh (e Oh My Zsh) è un'alternativa popolare e potente. I comandi della shell inclusi in questo post sono stati testati su bash su OS X (macOS) e dovrebbero funzionare anche con altre shell e ambienti.
Tutti gli esempi seguenti si basano sul dataset adult del repository UCI Machine Learning, noto anche come dataset "Census Income" e disponibile qui. Questo dataset è comunemente usato per prevedere se il reddito supera i \$50K/anno sulla base di dati censuari. Con 48842 righe e 14 attributi, non è affatto un dataset grande, ma è sufficiente per illustrare gli esempi. Sebbene i dati abbiano estensione .data, si tratta di un file CSV ben formattato. Sentiti libero di scaricare il dataset per seguire passo passo!
Conta con wc
Dato un nuovo file di testo, vuoi sapere quante righe contiene. Puoi farlo con il comando di conteggio parole wc -l:
Che ti dice che il file adult.data contiene 32562 righe. Il flag -l dice a wc di contare le righe. Puoi però usare wc anche per contare le parole usando il flag -w.
Il comando wc può anche contare il numero di file in una directory usando come input l'output di un semplice comando ls -l. Usare l'output di un comando come input di un altro comando mediante la pipe | è uno schema utile della shell chiamato pipelining. Lo vedrai in diversi esempi lungo questo post.
Supponi ora di avere una cartella con molti file. Il comando seguente ti dirà esattamente quanti file contiene:
Ci sono molte altre applicazioni per wc se inizi ad aggiungere wildcard e sottocartelle.
Torniamo al tuo file adult.data e guardiamo le prime righe con il comando head. Per impostazione predefinita, head stampa 10 righe; puoi limitare l'output alle prime 2 righe usando il flag -n.
E noti che il file non ha una riga di intestazione. I nomi delle colonne non sono presenti nel file. Puoi aggiungere quella riga di intestazione concatenando due file con il comando cat.
Concatena file con cat
Il comando cat stampa il contenuto di un file sullo standard output (cioè il tuo terminale). Può anche essere usato per concatenare una serie di file. Il comando cat file_1.csv file_2.csv > target_file.csv unirà il contenuto di file_1.csv e file_2.csv in target_file.csv, aggiungendo file_2.csv alla fine di file_1.csv.
Il file di intestazione non è nel dataset originale e devi crearlo. Per farlo, fai l'echo dell'elenco di nomi di colonne separati da virgola in un file header.csv.
$ echo"age,workclass,fnlwgt,education,education-num,marital-status,occupation,relationship,race,sex,capital-gain,capital-loss,native-country,class"> header.csvOfferto da
In questo esempio, hai usato il carattere di redirezione della shell > per riversare l'output di cat nel file adult.csv. Il > creerà un file o ne sostituirà completamente il contenuto se il file esiste già. Raddoppiando il simbolo >> aggiungerai il nuovo contenuto a un file già esistente senza cancellarne il contenuto.
Aggiungiamo ora il file header.csv all'inizio del file adult.data. Allo stesso tempo, rinomini adult.data in adult.csv visto che, in fin dei conti, è un file in formato CSV.
$ cat header.csv adult.data > adult.csv
Offerto da
Controlla che la prima riga di adult.csv contenga i nomi delle colonne con:
Un altro scenario frequente nel data mining si verifica quando un file è corrotto o formattato male, ad esempio con caratteri non UTF-8 o una virgola fuori posto. Puoi correggere quel file senza nemmeno aprirlo usando il comando sed.
Il pattern generico di sed è
$ sed"s/<string to replace>/<string to replace it with>/g"<source_file>><target_file>.Offerto da
Il dataset adult.csv usa il carattere ? per indicare un valore mancante. Puoi sostituire quel carattere con un valore di default più adatto usando sed. La stringa vuota è preferibile come indicazione di un valore mancante, poiché verrà interpretata come valore NaN quando carichi i dati in un DataFrame di Pandas.
Questo ti restituisce un conteggio di 2399 righe con almeno una colonna con un valore mancante indicato da ?. Il comando seguente sostituirà tutte le colonne con ? con una stringa vuota. Tutte le celle che contengono solo ?, seguito da uno spazio, ora saranno veramente vuote.
$ sed"s/, ?,/,,/g" adult.csv > adult.csvOfferto da
Nota che usi il delimitatore di colonna , nelle stringhe sorgente e destinazione per evitare di sostituire punti interrogativi legittimi che potrebbero essere presenti altrove nel dataset.
Sottocampionare un file grande
Immagina ora di avere a che fare con un file con oltre 30 milioni di righe. Mentre scrivi il tuo script in Python o R, vorrai testare il workflow solo su un campione di quel file originale di grandi dimensioni, senza dover caricare l'intero dataset in memoria. Puoi usare una combinazione di head e tail per creare un sottoinsieme del dataset originale.
head stampa la prima parte dei file;
tail stampa l'ultima parte dei file
Come hai visto prima, questi comandi accettano un flag -n, abbreviazione di --lines, che limita il numero di righe nell'output. tail accetta anche un flag -f, dove f sta per --follow, che stampa i dati man mano che nuove righe vengono aggiunte alla fine del file. Questo è particolarmente comodo per monitorare file di log mentre i tuoi script sono in esecuzione usando tail -f <logfile>.
Combinando la pipe | con head e tail, puoi estrarre un certo numero di righe dall'interno di un file sorgente ed esportarne il contenuto in un file di subset. Ad esempio, per estrarre 20 righe a partire dalla riga 100:
$ head-n120 adult.csv |tail-n20> adult_sample.csvOfferto da
Nota che prima prendi le first_line + number_of_lines con head e poi con tail prendi le number_of_lines. Il comando generico per il sottocampionamento è:
$ head -n <total_lines><source_file>| tail -n <number_of_lines>><target_file>Offerto da
dove total_lines = first_line + number_of_lines. Tuttavia, il tuo nuovo file campione non contiene più la riga di intestazione. Sappiamo già come aggiungere l'intestazione nel file di subset usando cat per concatenare il file di subset e il file header.csv creato prima:
$ cat adult_sample.csv header.csv > adult_sample_with_header.csv
Offerto da
Nota che non hai usato il nome del file sorgente adult\_sample.csv come nome del file di destinazione, ma hai invece creato un nuovo file chiamato adult\_sample\_with\_header.csv. Avere lo stesso nome di uno dei sorgenti e della destinazione mentre usi cat porterà a contenuti di file imprevisti. È meglio creare un nuovo file come output del comando cat.
Trovare i duplicati con uniq
Con il comando uniq puoi trovare righe ripetute adiacenti in un file. uniq accetta diversi flag, i più utili sono:
uniq -c: aggiunge il conteggio di ripetizione a ogni riga;
uniq -d: stampa solo le righe duplicate; e
uniq -u: stampa solo le righe uniche.
Tuttavia, uniq non è un comando "intelligente". Le righe ripetute non verranno rilevate se non sono adiacenti. Questo significa che prima devi sort il file. Questo comando conta il numero di righe duplicate in adult.csv.
e mostra che ci sono 23 duplicati. Il comando successivo prende l'output di tutte le righe con i conteggi di ripetizione aggiunti, ordina in ordine inverso e stampa i primi 3 duplicati:
Ci sono molte opzioni potenti che puoi ottenere combinando sort e uniq con diversi flag. Usa man sort e man uniq per esplorare ulteriormente questi comandi.
Selezionare colonne con cut
Il bello dei file CSV e dei comandi della shell è che puoi lavorare anche a livello di colonna usando cut per selezionare una colonna particolare. cut accetta due flag principali: -d per specificare il delimitatore di colonna e -f per specificare le colonne su cui vuoi lavorare. Nell'esempio seguente, usi cut per trovare il numero di valori unici assunti dalla variabile categorica workclass (colonna 2).
Per prima cosa seleziona la colonna workclass e manda in pipe a head per verificare di avere la colonna giusta:
$ cut-d","-f2 adult.csv |head-3
workclass
State-gov
Self-emp-not-incOfferto da
Ora, per contare gli unici, ordina l'output di cut e manda il risultato in pipe a uniq -c, così:
Che ti dice, per esempio, che hai 1837 valori nulli e che la classe principale è di gran lunga la classe Private con 22969 occorrenze.
La riga di comando sopra è simile al metodo value_counts() applicato a un DataFrame contenente i dati di adult.csv.
Loop
Finora hai lavorato principalmente su un file. Per rinominare, elaborare o trasferire grandi quantità di file, dovresti aggiungere i loop al tuo toolkit di shell. Il formato generico di un loop nella shell bash è:
Mettiamolo al lavoro. Immagina di avere 1000 file con spazi nel nome e di voler sostituire ogni spazio con un trattino basso "_".
replace_source=' 'replace_target='_'forfilenamein ./*.csv;donew_filename=${filename//$replace_source/$replace_target}mv"$filename""$new_filename"doneOfferto da
In questo esempio,
per prima cosa dichiari due variabili: replace_source e replace_target come segnaposto per lo spazio e il carattere di underscore
iteri su tutti i file *.csv nella cartella corrente
per ogni filename, crei un new_filename sostituendo ogni spazio con un underscore
e rinomini il file dal nome attuale al nuovo nome con il comando mv
In effetti, non solo hai usato la shell per ciclare attraverso i file in una directory, ma hai anche creato variabili.
Variabili
Concludiamo questa introduzione ai comandi della shell con le variabili. La creazione di variabili in shell si fa semplicemente così
$ varname='<a string>'
$ varname=a numberOfferto da
Nota che non ci sono spazi attorno al segno '='. var = '<a string>' non funzionerebbe. Per restituire il valore della variabile, fai semplicemente echo:
Scrivere loop e usare variabili apre la strada a manipolazioni di file più complesse ed è un punto di accesso alla scrittura di script di shell, che va oltre questo articolo introduttivo. Tuttavia, la shell script è abbastanza semplice se inizi in piccolo e migliori man mano che cresce la tua confidenza.
Conclusione
Le righe di comando della shell sono estremamente utili nel lavoro quotidiano da data scientist. Ci sono molti altri esempi e casi d'uso che si potrebbero esplorare. E come vedrai, spesso esistono diversi modi per ottenere un determinato risultato usando un'ampia gamma di comandi della shell e relativi flag. In questi casi, mantenere le cose semplici è sempre la strategia vincente.
Speriamo che gli esempi presentati qui ti aiutino a integrare i comandi della shell nel tuo toolkit di elaborazione dati. Sentiti libero di contattarmi e condividere i tuoi trucchi di shell su Twitter: @alexip.
Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Capita spesso di dover analizzare, modificare e processare rapidamente grandi quantità di file, sia per numero che per dimensioni. Spesso, però, si tratta di file di testo in formato CSV (Comma Separated Values). Aprirli con applicazioni foglio di calcolo come Excel, LibreOffice o OpenOffice sovraccarica la memoria della macchina. Inoltre, elaborare un gran numero di file in un unico batch spesso fallisce dopo qualche ora a causa di qualche anomalia imprevista in uno dei file.
Finisci inevitabilmente per passare molto tempo tra schermate bloccate, riavvii e lunghe attese.
Eppure, la maggior parte di queste operazioni può essere svolta con poche righe di codice. Ancora meglio, un po' di dimestichezza con alcune semplici righe di comando della shell può farti risparmiare tempo e ridurre la frustrazione.
Questo post offre una panoramica di alcuni comandi della shell che uso quasi ogni giorno. Spero ti siano utili.
Note rapide
Nota che esistono diversi tipi di shell (bash, zsh, ...), con bash la più comune poiché è la shell predefinita su OS X e sulle principali distribuzioni linux. Zsh (e Oh My Zsh) è un'alternativa popolare e potente. I comandi della shell inclusi in questo post sono stati testati su bash su OS X (macOS) e dovrebbero funzionare anche con altre shell e ambienti.
Tutti gli esempi seguenti si basano sul dataset adult del repository UCI Machine Learning, noto anche come dataset "Census Income" e disponibile qui. Questo dataset è comunemente usato per prevedere se il reddito supera i \$50K/anno sulla base di dati censuari. Con 48842 righe e 14 attributi, non è affatto un dataset grande, ma è sufficiente per illustrare gli esempi. Sebbene i dati abbiano estensione
.data, si tratta di un file CSV ben formattato. Sentiti libero di scaricare il dataset per seguire passo passo!Conta con
wcDato un nuovo file di testo, vuoi sapere quante righe contiene. Puoi farlo con il comando di conteggio parole
wc -l:Che ti dice che il file
adult.datacontiene 32562 righe. Il flag-ldice awcdi contare le righe. Puoi però usarewcanche per contare le parole usando il flag-w.Il file
adult.datacontiene quasi 500mila parole.Il comando
wcpuò anche contare il numero di file in una directory usando come input l'output di un semplice comandols -l. Usare l'output di un comando come input di un altro comando mediante la pipe|è uno schema utile della shell chiamato pipelining. Lo vedrai in diversi esempi lungo questo post.Supponi ora di avere una cartella con molti file. Il comando seguente ti dirà esattamente quanti file contiene:
Ci sono molte altre applicazioni per
wcse inizi ad aggiungere wildcard e sottocartelle.Torniamo al tuo file
adult.datae guardiamo le prime righe con il comandohead. Per impostazione predefinita,headstampa 10 righe; puoi limitare l'output alle prime 2 righe usando il flag-n.E noti che il file non ha una riga di intestazione. I nomi delle colonne non sono presenti nel file. Puoi aggiungere quella riga di intestazione concatenando due file con il comando
cat.Concatena file con
catIl comando
catstampa il contenuto di un file sullo standard output (cioè il tuo terminale). Può anche essere usato per concatenare una serie di file. Il comandocat file_1.csv file_2.csv > target_file.csvunirà il contenuto difile_1.csvefile_2.csvintarget_file.csv, aggiungendofile_2.csvalla fine difile_1.csv.Il file di intestazione non è nel dataset originale e devi crearlo. Per farlo, fai l'
echodell'elenco di nomi di colonne separati da virgola in un fileheader.csv.In questo esempio, hai usato il carattere di redirezione della shell
>per riversare l'output dicatnel fileadult.csv. Il>creerà un file o ne sostituirà completamente il contenuto se il file esiste già. Raddoppiando il simbolo>>aggiungerai il nuovo contenuto a un file già esistente senza cancellarne il contenuto.Aggiungiamo ora il file
header.csvall'inizio del fileadult.data. Allo stesso tempo, rinominiadult.datainadult.csvvisto che, in fin dei conti, è un file in formato CSV.Controlla che la prima riga di
adult.csvcontenga i nomi delle colonne con:Modifica un file con
sedUn altro scenario frequente nel data mining si verifica quando un file è corrotto o formattato male, ad esempio con caratteri non UTF-8 o una virgola fuori posto. Puoi correggere quel file senza nemmeno aprirlo usando il comando
sed.Il pattern generico di
sedèIl dataset
adult.csvusa il carattere?per indicare un valore mancante. Puoi sostituire quel carattere con un valore di default più adatto usandosed. La stringa vuota è preferibile come indicazione di un valore mancante, poiché verrà interpretata come valoreNaNquando carichi i dati in un DataFrame di Pandas.Questo ti restituisce un conteggio di 2399 righe con almeno una colonna con un valore mancante indicato da
?. Il comando seguente sostituirà tutte le colonne con?con una stringa vuota. Tutte le celle che contengono solo?, seguito da uno spazio, ora saranno veramente vuote.Nota che usi il delimitatore di colonna
,nelle stringhe sorgente e destinazione per evitare di sostituire punti interrogativi legittimi che potrebbero essere presenti altrove nel dataset.Sottocampionare un file grande
Immagina ora di avere a che fare con un file con oltre 30 milioni di righe. Mentre scrivi il tuo script in Python o R, vorrai testare il workflow solo su un campione di quel file originale di grandi dimensioni, senza dover caricare l'intero dataset in memoria. Puoi usare una combinazione di
headetailper creare un sottoinsieme del dataset originale.headstampa la prima parte dei file;tailstampa l'ultima parte dei fileCome hai visto prima, questi comandi accettano un flag
-n, abbreviazione di--lines, che limita il numero di righe nell'output.tailaccetta anche un flag-f, dovefsta per--follow, che stampa i dati man mano che nuove righe vengono aggiunte alla fine del file. Questo è particolarmente comodo per monitorare file di log mentre i tuoi script sono in esecuzione usandotail -f <logfile>.Combinando la pipe
|conheadetail, puoi estrarre un certo numero di righe dall'interno di un file sorgente ed esportarne il contenuto in un file di subset. Ad esempio, per estrarre 20 righe a partire dalla riga 100:Nota che prima prendi le first_line + number_of_lines con
heade poi contailprendi le number_of_lines. Il comando generico per il sottocampionamento è:dove
total_lines = first_line + number_of_lines. Tuttavia, il tuo nuovo file campione non contiene più la riga di intestazione. Sappiamo già come aggiungere l'intestazione nel file di subset usandocatper concatenare il file di subset e il fileheader.csvcreato prima:Nota che non hai usato il nome del file sorgente
adult\_sample.csvcome nome del file di destinazione, ma hai invece creato un nuovo file chiamatoadult\_sample\_with\_header.csv. Avere lo stesso nome di uno dei sorgenti e della destinazione mentre usicatporterà a contenuti di file imprevisti. È meglio creare un nuovo file come output del comandocat.Trovare i duplicati con
uniqCon il comando
uniqpuoi trovare righe ripetute adiacenti in un file.uniqaccetta diversi flag, i più utili sono:uniq -c: aggiunge il conteggio di ripetizione a ogni riga;uniq -d: stampa solo le righe duplicate; euniq -u: stampa solo le righe uniche.Tuttavia,
uniqnon è un comando "intelligente". Le righe ripetute non verranno rilevate se non sono adiacenti. Questo significa che prima devisortil file. Questo comando conta il numero di righe duplicate inadult.csv.e mostra che ci sono 23 duplicati. Il comando successivo prende l'output di tutte le righe con i conteggi di ripetizione aggiunti, ordina in ordine inverso e stampa i primi 3 duplicati:
Ci sono molte opzioni potenti che puoi ottenere combinando
sorteuniqcon diversi flag. Usaman sorteman uniqper esplorare ulteriormente questi comandi.Selezionare colonne con
cutIl bello dei file CSV e dei comandi della shell è che puoi lavorare anche a livello di colonna usando
cutper selezionare una colonna particolare.cutaccetta due flag principali:-dper specificare il delimitatore di colonna e-fper specificare le colonne su cui vuoi lavorare. Nell'esempio seguente, usicutper trovare il numero di valori unici assunti dalla variabile categoricaworkclass(colonna 2).Per prima cosa seleziona la colonna
workclasse manda in pipe a head per verificare di avere la colonna giusta:Ora, per contare gli unici, ordina l'output di cut e manda il risultato in pipe a
uniq -c, così:Che ti dice, per esempio, che hai 1837 valori nulli e che la classe principale è di gran lunga la classe
Privatecon 22969 occorrenze.La riga di comando sopra è simile al metodo
value_counts()applicato a un DataFrame contenente i dati diadult.csv.Loop
Finora hai lavorato principalmente su un file. Per rinominare, elaborare o trasferire grandi quantità di file, dovresti aggiungere i loop al tuo toolkit di shell. Il formato generico di un loop nella shell bash è:
Mettiamolo al lavoro. Immagina di avere 1000 file con spazi nel nome e di voler sostituire ogni spazio con un trattino basso "_".
In questo esempio,
replace_sourceereplace_targetcome segnaposto per lo spazio e il carattere di underscore*.csvnella cartella correntefilename, crei unnew_filenamesostituendo ogni spazio con un underscoremvIn effetti, non solo hai usato la shell per ciclare attraverso i file in una directory, ma hai anche creato variabili.
Variabili
Concludiamo questa introduzione ai comandi della shell con le variabili. La creazione di variabili in shell si fa semplicemente così
Per esempio:
Nota che non ci sono spazi attorno al segno '='.
var = '<a string>'non funzionerebbe. Per restituire il valore della variabile, fai semplicementeecho:E per usarla in uno script, incapsulala tra virgolette come visto prima:
Scrivere loop e usare variabili apre la strada a manipolazioni di file più complesse ed è un punto di accesso alla scrittura di script di shell, che va oltre questo articolo introduttivo. Tuttavia, la shell script è abbastanza semplice se inizi in piccolo e migliori man mano che cresce la tua confidenza.
Conclusione
Le righe di comando della shell sono estremamente utili nel lavoro quotidiano da data scientist. Ci sono molti altri esempi e casi d'uso che si potrebbero esplorare. E come vedrai, spesso esistono diversi modi per ottenere un determinato risultato usando un'ampia gamma di comandi della shell e relativi flag. In questi casi, mantenere le cose semplici è sempre la strategia vincente.
Speriamo che gli esempi presentati qui ti aiutino a integrare i comandi della shell nel tuo toolkit di elaborazione dati. Sentiti libero di contattarmi e condividere i tuoi trucchi di shell su Twitter: @alexip.
Dai un'occhiata al nostro tutorial Configura un ambiente di data science sul tuo computer.