Tubi e filtri
Ultimo aggiornamento il 2025-11-07 | Modifica questa pagina
Tempo stimato: 35 minuti
Panoramica
Domande
- Come posso combinare i comandi esistenti per produrre l’output desiderato?
- Come posso mostrare solo una parte dell’output?
Obiettivi
- Spiegare il vantaggio di collegare i comandi con pipe e filtri.
- Combinare sequenze di comandi per ottenere un nuovo output
- Reindirizzare l’output di un comando a un file.
- Spiegate cosa succede di solito se a un programma o a una pipeline non viene dato alcun input da elaborare.
Ora che conosciamo alcuni comandi di base, possiamo finalmente
esaminare la caratteristica più potente della shell: la facilità con cui
ci permette di combinare programmi esistenti in modi nuovi. Inizieremo
con la cartella shell-lesson-data/exercise-data/alkanes che
contiene sei file che descrivono alcune semplici molecole organiche.
L’estensione .pdb indica che questi file sono in formato
Protein Data Bank, un semplice formato di testo che specifica il tipo e
la posizione di ogni atomo nella molecola.
OUTPUT
cubane.pdb methane.pdb pentane.pdb
ethane.pdb octane.pdb propane.pdb
Eseguiamo un comando di esempio:
OUTPUT
20 156 1158 cubane.pdb
wc è il comando “contaparole”: conta il numero di righe,
parole e caratteri nei file (restituendo i valori in questo ordine, da
sinistra a destra).
Se si esegue il comando wc *.pdb, il * in
*.pdb corrisponde a zero o più caratteri, quindi la shell
trasforma *.pdb in un elenco di tutti i file
.pdb nella cartella corrente:
OUTPUT
20 156 1158 cubane.pdb
12 84 622 ethane.pdb
9 57 422 methane.pdb
30 246 1828 octane.pdb
21 165 1226 pentane.pdb
15 111 825 propane.pdb
107 819 6081 total
Si noti che wc *.pdb mostra anche il numero totale di
tutte le righe nell’ultima riga dell’output.
Se si esegue wc -l invece di wc, l’output
mostra solo il numero di righe per file:
OUTPUT
20 cubane.pdb
12 ethane.pdb
9 methane.pdb
30 octane.pdb
21 pentane.pdb
15 propane.pdb
107 total
Le opzioni -m e -w possono essere usate
anche con il comando wc per mostrare rispettivamente solo
il numero di caratteri o il numero di parole.
Perché non fa nulla?
Cosa succede se un comando deve elaborare un file, ma non gli viene assegnato un nome? Ad esempio, cosa succede se digitiamo:
ma non digita *.pdb (o qualsiasi altra cosa) dopo il
comando? Poiché non ha alcun nome di file, wc presume di
dover elaborare l’input dato dal prompt dei comandi, quindi se ne sta lì
ad aspettare che gli si forniscano dei dati in modo interattivo.
Dall’esterno, però, tutto ciò che si vede è che è seduto lì e il comando
non sembra fare nulla.
Se commettete questo tipo di errore, potete uscire da questo stato tenendo premuto il tasto control (Ctrl) e premendo una volta la lettera C: Ctrl+C. Quindi rilasciare entrambi i tasti.
Cattura dell’output da comandi
Quale di questi file contiene il minor numero di righe? È facile rispondere a questa domanda quando ci sono solo sei file, ma se ce ne fossero 6000? Il primo passo verso la soluzione consiste nell’eseguire il comando:
Il simbolo maggiore di, >, indica alla shell di
reindirizzare l’output del comando a un file invece di
stamparlo sullo schermo. Questo comando non stampa alcun output sullo
schermo, perché tutto ciò che wc avrebbe stampato è andato
invece nel file lengths.txt. Se il file non esiste prima
dell’emissione del comando, la shell lo creerà. Se il file esiste già,
verrà sovrascritto silenziosamente, con conseguente perdita di dati.
Pertanto, i comandi redirect richiedono cautela.
ls lengths.txt conferma che il file esiste:
OUTPUT
lengths.txt
Ora possiamo inviare il contenuto di lengths.txt allo
schermo usando cat lengths.txt. Il comando cat
prende il nome da ‘concatenate’, cioè unire insieme, e stampa il
contenuto dei file uno dopo l’altro. In questo caso c’è un solo file,
quindi cat ci mostra solo ciò che contiene:
OUTPUT
20 cubane.pdb
12 ethane.pdb
9 methane.pdb
30 octane.pdb
21 pentane.pdb
15 propane.pdb
107 total
Output Pagina per Pagina
In questa lezione continueremo a usare cat per comodità
e coerenza, ma ha lo svantaggio di scaricare sempre l’intero file sullo
schermo. Più utile nella pratica è il comando less (ad
esempio less lengths.txt). Questo comando visualizza una
schermata del file e poi si ferma. Si può andare avanti di una schermata
premendo la barra spaziatrice, o indietro di una premendo
b. Premere q per uscire.
Filtraggio dell’output
Il prossimo passo sarà quello di usare il comando sort
per ordinare il contenuto del file lengths.txt. Ma prima
faremo un esercizio per imparare qualcosa sul comando sort:
Cosa fa sort -n?
Il file shell-lesson-data/exercise-data/numbers.txt
contiene le seguenti righe:
10
2
19
22
6
Se eseguiamo sort su questo file, l’output è:
OUTPUT
10
19
2
22
6
Se si esegue sort -n sullo stesso file, si ottiene
invece questo:
OUTPUT
2
6
10
19
22
Spiegare perché -n ha questo effetto.
L’opzione -n specifica un ordinamento numerico anziché
alfanumerico.
Useremo anche l’opzione -n per specificare che
l’ordinamento è numerico invece che alfanumerico. Questo non modifica il
file, ma invia il risultato dell’ordinamento allo schermo:
OUTPUT
9 methane.pdb
12 ethane.pdb
15 propane.pdb
20 cubane.pdb
21 pentane.pdb
30 octane.pdb
107 total
Possiamo mettere l’elenco ordinato di righe in un altro file
temporaneo chiamato sorted-lengths.txt mettendo
> sorted-lengths.txt dopo il comando, proprio come
abbiamo usato > lengths.txt per mettere l’output di
wc in lengths.txt. Una volta fatto questo, si
può eseguire un altro comando chiamato head per ottenere le
prime righe in sorted-lengths.txt:
OUTPUT
9 methane.pdb
L’uso di -n 1 con head indica che vogliamo
solo la prima riga del file; -n 20 otterrebbe le prime 20 e
così via. Poiché sorted-lengths.txt contiene le lunghezze
dei file ordinate dalla minore alla maggiore, l’output di
head deve essere il file con il minor numero di righe.
Cosa significa >>?
Abbiamo visto l’uso di >, ma esiste un operatore
simile >> che funziona in modo leggermente diverso.
Impareremo le differenze tra questi due operatori stampando alcune
stringhe. Possiamo usare il comando echo per stampare delle
stringhe, ad esempio
OUTPUT
The echo command prints text
Ora provate i comandi sottostanti per scoprire la differenza tra i due operatori:
e:
Suggerimento: provate a eseguire ogni comando due volte di seguito e poi esaminate i file di output.
Nel primo esempio con >, la stringa ‘hello’ viene
scritta in testfile01.txt, ma il file viene sovrascritto
ogni volta che si esegue il comando.
Vediamo dal secondo esempio che anche l’operatore
>> scrive ‘hello’ in un file (in questo caso
testfile02.txt), ma aggiunge la stringa al file se questo
esiste già (cioè quando lo eseguiamo per la seconda volta).
Applicazione dei dati
Abbiamo già incontrato il comando head, che stampa le
righe dall’inizio di un file. il comando tail è simile, ma
stampa le righe dalla fine di un file.
Considerare il file
shell-lesson-data/exercise-data/animal-counts/animals.csv.
Dopo questi comandi, selezionare la risposta che corrisponde al file
animals-subset.csv:
- Le prime tre righe di
animals.csv - le ultime due righe di
animals.csv - Le prime tre righe e le ultime due righe di
animals.csv - La seconda e la terza riga di
animals.csv
L’opzione 3 è corretta. Affinché l’opzione 1 sia corretta, si deve
eseguire solo il comando head. Per l’opzione 2 è corretto
eseguire solo il comando tail. Affinché l’opzione 4 sia
corretta, occorre eseguire il pipe dell’output di head in
tail -n 2 facendo
head -n 3 animals.csv | tail -n 2 > animals-subset.csv
Passaggio dell’output a un altro comando
Nel nostro esempio di ricerca del file con il minor numero di righe,
stiamo usando due file intermedi lengths.txt e
sorted-lengths.txt per memorizzare l’output. Questo è un
modo confuso di lavorare, perché anche una volta capito cosa fanno
wc, sort e head, questi file
intermedi rendono difficile capire cosa sta succedendo. Si può
semplificare la comprensione eseguendo sort e
head insieme:
OUTPUT
9 methane.pdb
La barra verticale, |, tra i due comandi è chiamata
pipe. Indica alla shell che vogliamo usare l’output del
comando a sinistra come input del comando a destra.
Questo ha eliminato la necessità del file
sorted-lengths.txt.
Combinazione di più comandi
Nulla ci impedisce di concatenare le pipe consecutivamente. Ad
esempio, possiamo inviare l’output di wc direttamente a
sort, e poi inviare l’output risultante a
head. Questo elimina la necessità di file intermedi.
Inizieremo usando una pipe per inviare l’output di wc a
sort:
OUTPUT
9 methane.pdb
12 ethane.pdb
15 propane.pdb
20 cubane.pdb
21 pentane.pdb
30 octane.pdb
107 total
Possiamo quindi inviare l’output attraverso un’altra pipe, a
head, in modo che la pipeline completa diventi:
OUTPUT
9 methane.pdb
Questo è esattamente come un matematico che annida funzioni come
log(3x) e dice “il log di tre volte x”. Nel nostro
caso, l’algoritmo è “testa dell’ordinamento del numero di righe di
*.pdb”.
Il reindirizzamento e le pipe utilizzate negli ultimi comandi sono illustrati di seguito:
{alt=‘Redirects and Pipes di
diversi comandi: “wc -l *.pdb” indirizzerà l’output alla shell. “wc -l
*.pdb > lunghezze” dirige l’output al file “lunghezze”. “wc -l *.pdb
| sort -n | head -n 1” crea una pipeline in cui l’output del comando
“wc” è l’input del comando “sort”, l’output del comando “sort” è l’input
del comando “head” e l’output del comando “head” è diretto alla
shell’}
Comandi piping insieme
Nella nostra cartella corrente, vogliamo trovare i 3 file che hanno il minor numero di righe. Quale comando elencato di seguito potrebbe funzionare?
wc -l * > sort -n > head -n 3wc -l * | sort -n | head -n 1-3wc -l * | head -n 3 | sort -nwc -l * | sort -n | head -n 3
L’opzione 4 è la soluzione. Il carattere pipe | viene
usato per collegare l’uscita di un comando all’ingresso di un altro. il
carattere > è usato per reindirizzare l’output standard
a un file. Provatelo nella cartella
shell-lesson-data/exercise-data/alkanes!
Strumenti progettati per funzionare insieme
Questa idea di collegare i programmi tra loro è il motivo per cui
Unix ha avuto tanto successo. Invece di creare programmi enormi che
cercano di fare molte cose diverse, i programmatori Unix si concentrano
sulla creazione di molti strumenti semplici che svolgono bene un lavoro
ciascuno e che funzionano bene tra loro. Questo modello di
programmazione è chiamato “pipe e filtri”. Abbiamo già visto le pipe; un
filtro è un programma come wc o
sort che trasforma un flusso di input in un flusso di
output. Quasi tutti gli strumenti standard di Unix possono funzionare in
questo modo. A meno che non venga detto di fare diversamente, essi
leggono dallo standard input, fanno qualcosa con ciò che hanno letto e
scrivono sullo standard output.
La chiave è che ogni programma che legge righe di testo dallo standard input e scrive righe di testo sullo standard output può essere combinato con ogni altro programma che si comporta in questo modo. Potete e dovreste scrivere i vostri programmi in questo modo, in modo che voi e altre persone possiate inserire quei programmi nelle pipe per moltiplicarne la potenza.
Comprensione della lettura di pipe
Un file chiamato animals.csv (nella cartella
shell-lesson-data/exercise-data/animal-counts) contiene i
seguenti dati:
2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-06,fox,4
2012-11-07,rabbit,16
2012-11-07,bear,1
Quale testo passa attraverso ciascuna delle pipe e il redirect finale
nella pipeline sottostante? Si noti che il comando sort -r
ordina in ordine inverso.
Suggerimento: costruite la pipeline un comando alla volta per verificare la vostra comprensione
Il comando head estrae le prime 5 righe da
animals.csv. Poi, le ultime 3 righe vengono estratte dalle
precedenti 5 usando il comando tail. Con il comando
sort -r queste 3 righe vengono ordinate in ordine inverso.
Infine, l’output viene reindirizzato in un file: final.txt.
Il contenuto di questo file può essere controllato eseguendo il comando
cat final.txt. Il file dovrebbe contenere le seguenti
righe:
2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-05,raccoon,7
Costruzione di un tubo
Per il file animals.csv dell’esercizio precedente,
considerate il seguente comando:
Il comando cut è usato per rimuovere o “tagliare” certe
sezioni di ogni riga del file, e cut si aspetta che le
righe siano separate in colonne da un carattere Tab. Un
carattere usato in questo modo è chiamato delimitatore.
Nell’esempio precedente si usa l’opzione -d per specificare
la virgola come carattere delimitatore. Abbiamo anche usato l’opzione
-f per specificare che vogliamo estrarre il secondo campo
(colonna). Si ottiene così il seguente risultato:
OUTPUT
deer
rabbit
raccoon
rabbit
deer
fox
rabbit
bear
Il comando uniq filtra le righe adiacenti corrispondenti
in un file. Come si potrebbe estendere questa pipeline (usando
uniq e un altro comando) per scoprire quali animali
contiene il file (senza duplicati nei loro nomi)?
Quale tubo?
Il file animals.csv contiene 8 righe di dati formattati
come segue:
OUTPUT
2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
...
Il comando uniq ha un’opzione -c che
fornisce un conteggio del numero di volte in cui una riga è presente nel
suo input. Supponendo che la vostra directory corrente sia
shell-lesson-data/exercise-data/animal-counts, quale
comando usereste per produrre una tabella che mostri il numero totale di
ogni tipo di animale nel file?
sort animals.csv | uniq -csort -t, -k2,2 animals.csv | uniq -ccut -d, -f 2 animals.csv | uniq -ccut -d, -f 2 animals.csv | sort | uniq -ccut -d, -f 2 animals.csv | sort | uniq -c | wc -l
L’opzione 4. è la risposta corretta. Se avete difficoltà a capire
perché, provate a eseguire i comandi o le sottosezioni delle pipeline
(assicuratevi di essere nella cartella
shell-lesson-data/exercise-data/animal-counts).
Pipeline di Nelle: Controllo dei file
Nelle ha fatto passare i suoi campioni attraverso le macchine di
analisi e ha creato 17 file nella cartella
north-pacific-gyre descritta in precedenza. Per un rapido
controllo, partendo dalla cartella shell-lesson-data, Nelle
digita:
l’output è costituito da 18 righe che assomigliano a queste:
OUTPUT
300 NENE01729A.txt
300 NENE01729B.txt
300 NENE01736A.txt
300 NENE01751A.txt
300 NENE01751B.txt
300 NENE01812A.txt
... ...
Ora digita questo:
OUTPUT
240 NENE02018B.txt
300 NENE01729A.txt
300 NENE01729B.txt
300 NENE01736A.txt
300 NENE01751A.txt
Ops: uno dei file è 60 righe più corto degli altri. Quando torna indietro e controlla, vede che ha fatto quel saggio alle 8:00 di lunedì mattina — probabilmente qualcuno ha usato la macchina nel fine settimana e lei ha dimenticato di resettarla. Prima di rieseguire il campione, controlla se qualche file ha troppi dati:
OUTPUT
300 NENE02040B.txt
300 NENE02040Z.txt
300 NENE02043A.txt
300 NENE02043B.txt
5040 total
I numeri sembrano buoni, ma cosa ci fa quella “Z” nella terzultima riga? Tutti i suoi campioni dovrebbero essere contrassegnati con ‘A’ o ‘B’; per convenzione, il suo laboratorio usa la ‘Z’ per indicare i campioni con informazioni mancanti. Per trovare altri campioni simili, fa così:
OUTPUT
NENE01971Z.txt NENE02040Z.txt
Quando controlla il registro sul suo portatile, non c’è alcuna
profondità registrata per nessuno dei due campioni. Poiché è troppo
tardi per ottenere le informazioni in altro modo, deve escludere questi
due file dalla sua analisi. Potrebbe eliminarli usando rm,
ma in realtà ci sono analisi che potrebbe fare in seguito in cui la
profondità non è importante, quindi dovrà fare attenzione a selezionare
i file usando le espressioni jolly
NENE*A.txt NENE*B.txt.
Rimozione dei file non necessari
Supponiamo di voler cancellare i file dei dati elaborati e di voler
conservare solo i file grezzi e lo script di elaborazione per
risparmiare spazio. I file grezzi terminano in .dat e
quelli elaborati in .txt. Quale delle seguenti operazioni
rimuoverà tutti i file di dati elaborati e solo i file di dati
elaborati?
rm ?.txtrm *.txtrm * .txtrm *.*
- Questo rimuove i file
.txtcon nomi di un solo carattere - Questa è la risposta corretta
- La shell espanderebbe
*per far corrispondere tutto ciò che si trova nella cartella corrente, quindi il comando cercherebbe di rimuovere tutti i file corrispondenti e un file aggiuntivo chiamato.txt - La shell espande
*.*per far corrispondere tutti i nomi di file contenenti almeno un., compresi i file elaborati (.txt) e i file grezzi (.dat)
-
wcconta righe, parole e caratteri nei suoi input. -
catmostra il contenuto dei suoi input. -
sortordina i suoi input. -
headvisualizza le prime 10 righe del suo input per impostazione predefinita, senza ulteriori argomenti. -
tailvisualizza le ultime 10 righe del suo input per impostazione predefinita, senza ulteriori argomenti. -
command > [file]reindirizza l’output di un comando a un file (sovrascrivendo qualsiasi contenuto esistente). -
command >> [file]aggiunge l’output di un comando a un file. -
[first] | [second]è una pipeline: l’output del primo comando viene usato come input del secondo. - Il modo migliore per usare la shell è usare le pipe per combinare semplici programmi monouso (filtri).