Content from Introduzione alla shell
Ultimo aggiornamento il 2025-11-07 | Modifica questa pagina
Tempo stimato: 5 minuti
Panoramica
Domande
- Cos’è una shell di comando e perché dovrei usarla?
Obiettivi
- Spiegare come la shell si relaziona con la tastiera, lo schermo, il sistema operativo e i programmi degli utenti.
- Spiegare quando e perché si dovrebbero usare le interfacce a riga di comando invece delle interfacce grafiche.
Sfondo
L’uomo e il computer interagiscono comunemente in molti modi diversi, ad esempio tramite tastiera e mouse, interfacce touch screen o sistemi di riconoscimento vocale. Il modo più diffuso di interagire con i computer è chiamato interfaccia grafica (graphical user interface GUI). Con una GUI, le istruzioni vengono impartite facendo clicK con il mouse e utilizzando interazioni guidate da menu.
Sebbene l’aiuto visivo di un’interfaccia grafica ne renda intuitivo l’apprendimento, questo modo di fornire istruzioni a un computer è poco scalabile. Immaginate il seguente compito: per una ricerca bibliografica, dovete copiare la terza riga di mille file di testo in mille directory diverse e incollarla in un unico file. Utilizzando un’interfaccia grafica, non solo dovreste cliccare alla vostra scrivania per diverse ore, ma potreste anche commettere un errore nel completare questo compito ripetitivo. È qui che possiamo tratte vantaggio della shell Unix. La shell Unix è sia un’interfaccia a riga di comando (CLI) che un linguaggio di scripting, che consente di svolgere tali compiti ripetitivi in modo automatico e veloce. Con i comandi appropriati, la shell può ripetere le operazioni con o senza modifiche tutte le volte che si vuole. Utilizzando la shell, l’operazione descritta nell’esempio di letteratura può essere eseguita in pochi secondi.
La shell
La shell è un programma in cui gli utenti possono digitare comandi. Con la shell è possibile richiamare programmi complicati come il software di modellazione climatica o semplici comandi che creano una directory vuota con una sola riga di codice. La shell Unix più diffusa è Bash (Bourne Again SHell — così chiamata perché deriva da una shell scritta da Stephen Bourne). Bash è la shell predefinita nella maggior parte delle moderne implementazioni Unix e nella maggior parte dei pacchetti che forniscono strumenti simili a Unix per Windows. Si noti che “Git Bash” è un software che consente agli utenti di Windows di utilizzare un’interfaccia simile a Bash quando interagiscono con Git.
L’uso della shell richiede un certo sforzo e un po’ di tempo per essere appreso. Mentre l’interfaccia grafica presenta delle scelte da selezionare, le scelte della CLI non vengono presentate automaticamente, quindi è necessario imparare alcuni comandi come un nuovo vocabolario in una lingua che si sta studiando. Tuttavia, a differenza di una lingua parlata, un piccolo numero di “parole” (cioè di comandi) permette di fare molta strada e oggi ci occuperemo di questi pochi elementi essenziali.
La grammatica di una shell consente di combinare gli strumenti esistenti in potenti pipeline e di gestire automaticamente grandi volumi di dati. Le sequenze di comandi possono essere scritte in un script, migliorando la riproducibilità dei flussi di lavoro.
Inoltre, la riga di comando è spesso il modo più semplice per interagire con macchine e supercomputer remoti. La familiarità con la shell è quasi essenziale per eseguire una serie di strumenti e risorse specializzate, compresi i sistemi di calcolo ad alte prestazioni. Con l’aumento della popolarità dei cluster e dei sistemi di cloud computing per l’elaborazione di dati scientifici, la capacità di interagire con la shell sta diventando un’abilità necessaria. Possiamo basarci sulle competenze della riga di comando qui trattate per affrontare un’ampia gamma di domande scientifiche e sfide computazionali.
Iniziamo.
Quando la shell viene aperta per la prima volta, viene visualizzato un prompt, che indica che la shell è in attesa di input.
La shell usa tipicamente $ il segno del dollaro come
prompt, ma può usare un simbolo diverso. Negli esempi di questa lezione,
mostreremo il prompt come $. La cosa più importante è
non digitare il prompt quando si digitano i comandi. Digitate
solo il comando che segue il prompt. Questa regola si applica sia in
queste lezioni che in quelle di altre fonti. Si noti inoltre che dopo
aver digitato un comando, è necessario premere il tasto Invio
per eseguirlo.
Il prompt è seguito da un cursore di testo, un carattere che indica la posizione in cui verrà visualizzata la digitazione. Il cursore è solitamente un blocco lampeggiante o fisso, ma può anche essere un trattino basso o una pipe. Lo si può vedere in un programma di editor di testo, ad esempio.
Si noti che il prompt potrebbe avere un aspetto leggermente diverso.
In particolare, gli ambienti di shell più diffusi mettono per default il
nome dell’utente e il nome dell’host prima di $. Un prompt
di questo tipo potrebbe apparire come, ad esempio:
Il prompt potrebbe includere anche più di questo. Non preoccupatevi
se il vostro prompt non è solo un breve $. Questa lezione
non dipende da queste informazioni aggiuntive e non dovrebbe nemmeno
ostacolarvi. L’unico elemento importante su cui concentrarsi è il
carattere $ stesso e vedremo più avanti perché.
Proviamo il nostro primo comando, ls, abbreviazione di
listing. Questo comando elencherà il contenuto della directory
corrente:
OUTPUT
Desktop Downloads Movies Pictures
Documents Library Music Public
Comando non trovato
La pipeline di Nelle: Un problema tipico
Nelle Nemo, una biologa marina, è appena tornata da un’indagine di
sei mesi nel North Pacific
Gyre, dove ha campionato la vita marina gelatinosa nel Great
Pacific Garbage Patch. Ha 1520 campioni che ha analizzato per
misurare l’abbondanza relativa di 300 proteine. Deve far passare questi
1520 file attraverso un programma immaginario chiamato
goostats.sh. Oltre a questo enorme compito, deve scrivere i
risultati entro la fine del mese, in modo che il suo articolo possa
apparire in un numero speciale di Aquatic Goo Letters.
Se Nelle dovesse scegliere di eseguire goostats.sh a
mano utilizzando un’interfaccia grafica, dovrà selezionare e aprire un
file 1520 volte. Se goostats.sh impiega 30 secondi per
eseguire ogni file, l’intero processo richiederà più di 12 ore
dell’attenzione di Nelle. Con la shell, Nelle può invece assegnare al
computer questo compito banale mentre si concentra sulla stesura del suo
articolo.
Le prossime lezioni esploreranno i modi in cui Nelle può raggiungere
questo obiettivo. In particolare, le lezioni spiegano come Nelle possa
utilizzare una shell di comando per eseguire il programma
goostats.sh, utilizzando dei loop per automatizzare i
passaggi ripetitivi di inserimento dei nomi dei file, in modo che il suo
computer possa lavorare mentre lei scrive il suo articolo.
Una volta messa insieme una pipeline di elaborazione, sarà in grado di riutilizzarla ogni volta che raccoglierà altri dati.
Per svolgere il suo compito, Nelle deve sapere come fare:
- navigare in un file o in una cartella
- creare un file o una cartella
- verifica la lunghezza di un file
- concatenare i comandi tra loro
- recuperare un insieme di file
- iterazione di file
- esegue uno script di shell contenente la sua pipeline
- Una shell è un programma il cui scopo principale è leggere i comandi ed eseguire altri programmi.
- Questa lezione utilizza Bash, la shell predefinita in molte implementazioni di Unix.
- I programmi possono essere eseguiti in Bash inserendo i comandi nel prompt della riga di comando.
- I principali vantaggi della shell sono l’elevato rapporto tra azioni e battute, il supporto per l’automazione di attività ripetitive e la capacità di accedere a macchine in rete.
- Una sfida significativa nell’uso della shell può essere quella di sapere quali comandi devono essere eseguiti e come eseguirli.
Content from Navigazione tra file e directory
Ultimo aggiornamento il 2025-11-07 | Modifica questa pagina
Tempo stimato: 40 minuti
Panoramica
Domande
- Come posso muovermi nel mio computer?
- Come posso vedere quali file e cartelle ci sono?
- Come posso specificare la posizione di un file o di una cartella sul mio computer?
Obiettivi
- Spiegare le somiglianze e le differenze tra un file e una directory.
- Tradurre un percorso assoluto in un percorso relativo e viceversa.
- Costruire percorsi assoluti e relativi che identificano file e cartelle specifici.
- Usare opzioni e argomenti per modificare il comportamento di un comando di shell.
- Dimostrare l’uso del completamento a schede e spiegarne i vantaggi.
L’introduzione e la navigazione del filesystem nella shell (trattata nella sezione Navigare tra file e directory) può creare confusione. Si possono tenere aperti fianco a fianco sia il terminale che il file explorer della GUI, in modo che gli studenti possano vedere il contenuto e la struttura dei file mentre usano il terminale per navigare nel sistema.
La parte del sistema operativo responsabile della gestione dei file e delle directory si chiama file system. Organizza i dati in file, che contengono informazioni, e cartelle, che contengono file o altre cartelle.
Diversi comandi sono usati frequentemente per creare, ispezionare, rinominare e cancellare file e cartelle. Per iniziare a esplorarli, andiamo alla nostra finestra di shell aperta.
Per prima cosa, scopriamo dove ci troviamo eseguendo un comando
chiamato pwd (che sta per ‘print working directory’). Le
directory sono come luoghi: in qualsiasi momento, mentre si
utilizza la shell, ci si trova esattamente in un luogo chiamato
current working directory. I comandi leggono e scrivono
i file nella directory di lavoro corrente, cioè “qui”, quindi è
importante sapere dove ci si trova prima di eseguire un comando.
pwd mostra la posizione in cui ci si trova:
OUTPUT
/Users/nelle
Qui, la risposta del computer è /Users/nelle, che è la
home directory di Nelle:
Variazione della directory principale
Il percorso della home directory ha un aspetto diverso nei diversi
sistemi operativi. Su Linux, può apparire come /home/nelle,
mentre su Windows sarà simile a
C:\Documents and Settings\nelle o
C:\Users\nelle. (Negli esempi futuri, abbiamo utilizzato
l’output del Mac come predefinito; l’output di Linux e Windows può
differire leggermente, ma dovrebbe essere generalmente simile.
Si suppone inoltre che il comando pwd restituisca la
home directory dell’utente. Se pwd restituisce qualcosa di
diverso, potrebbe essere necessario navigare lì usando cd o
alcuni comandi di questa lezione non funzioneranno come scritto. Vedere
Esplorare altre directory per
maggiori dettagli sul comando cd.
Per capire che cos’è una “cartella home”, diamo un’occhiata a come è organizzato il file system nel suo complesso. Per il bene di questo esempio, illustreremo il filesystem del computer della nostra scienziata Nelle. Dopo questa illustrazione, imparerete i comandi per esplorare il vostro filesystem, che sarà costruito in modo simile, ma non esattamente identico.
Sul computer di Nelle, il filesystem ha questo aspetto:
Il filesystem ha l’aspetto di un albero capovolto. La cartella più in
alto è la cartella di root che contiene tutto il resto.
Ci si riferisce ad essa usando un carattere slash, /, da
solo; questo carattere è lo slash iniziale di
/Users/nelle.
All’interno di questa cartella ci sono diverse altre cartelle:
bin (dove sono memorizzati alcuni programmi integrati),
data (per i file di dati vari), Users (dove si
trovano le cartelle personali degli utenti), tmp (per i
file temporanei che non devono essere memorizzati a lungo) e così
via.
Sappiamo che la nostra cartella di lavoro corrente
/Users/nelle è memorizzata all’interno di
/Users perché /Users è la prima parte del suo
nome. Allo stesso modo, sappiamo che /Users è memorizzata
nella cartella principale / perché il suo nome inizia con
/.
Slash
Si noti che il carattere / ha due significati. Quando
compare davanti al nome di un file o di una cartella, si riferisce alla
cartella principale. Quando appare all’interno di un percorso,
è solo un separatore.
Sotto /Users, troviamo una directory per ogni utente con
un account sulla macchina di Nelle, i suoi colleghi imhotep e
larry.
I file dell’utente imhotep sono memorizzati in
/Users/imhotep, quelli dell’utente larry in
/Users/larry e quelli di Nelle in
/Users/nelle. Nelle è l’utente degli esempi; pertanto, la
nostra cartella home è /Users/nelle. In genere, quando si
apre un nuovo prompt dei comandi, all’inizio ci si trova nella propria
cartella home.
Ora impariamo il comando che ci permetterà di vedere il contenuto del
nostro filesystem. Possiamo vedere cosa c’è nella nostra cartella home
eseguendo ls:
OUTPUT
Applications Documents Library Music Public
Desktop Downloads Movies Pictures
(Anche in questo caso, i risultati possono essere leggermente diversi a seconda del sistema operativo e di come è stato personalizzato il filesystem)
ls stampa i nomi dei file e delle cartelle nella
cartella corrente. È possibile rendere il suo output più comprensibile
utilizzando l’opzione -F **che indica a ls di
classificare l’output aggiungendo un marcatore ai nomi dei file e delle
cartelle per indicare di cosa si tratta:
- il trattino
/indica che si tratta di una directory -
@indica un link -
*indica un eseguibile
A seconda delle impostazioni predefinite della shell, questa potrebbe anche utilizzare dei colori per indicare se ogni voce è un file o una cartella.
OUTPUT
Applications/ Documents/ Library/ Music/ Public/
Desktop/ Downloads/ Movies/ Pictures/
Qui possiamo vedere che la cartella home contiene solo sottocartelle. Tutti i nomi nell’output che non hanno un simbolo di classificazione sono file nella cartella di lavoro corrente.
Cancellazione del terminale
Se lo schermo è troppo ingombro, si può cancellare il terminale con
il comando clear. È comunque possibile accedere ai comandi
precedenti usando ↑ e ↓ per spostarsi riga per
riga, oppure scorrendo il terminale.
Ottenere aiuto
ls ha molte altre opzioni. Ci sono due
modi comuni per scoprire come usare un comando e quali opzioni accetta —
a seconda del vostro ambiente, potreste scoprire che solo uno di
questi modi funziona:
- possiamo passare un’opzione
--helpa qualsiasi comando (disponibile su Linux e Git Bash), ad esempio:
- possiamo leggere il suo manuale con
man(disponibile su Linux e macOS):
descriveremo entrambi i modi in seguito.
Guida per i comandi incorporati
Alcuni comandi sono integrati nella shell Bash, anziché esistere come
programmi separati nel filesystem. Un esempio è il comando
cd (cambio di directory). Se si riceve un messaggio come
No manual entry for cd, provare invece
help cd. Il comando help è il modo per
ottenere informazioni sull’uso di Bash
built-ins.
L’opzione --help è stata utilizzata per elencare i
contenuti della cartella di lavoro corrente
La maggior parte dei comandi di bash e dei programmi scritti per
essere eseguiti all’interno di bash supportano un’opzione
--help che mostra ulteriori informazioni su come utilizzare
il comando o il programma.
OUTPUT
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if neither -cftuvSUX nor --sort is specified.
Mandatory arguments to long options are mandatory for short options, too.
-a, --all do not ignore entries starting with .
-A, --almost-all do not list implied . and ..
--author with -l, print the author of each file
-b, --escape print C-style escapes for nongraphic characters
--block-size=SIZE scale sizes by SIZE before printing them; e.g.,
'--block-size=M' prints sizes in units of
1,048,576 bytes; see SIZE format below
-B, --ignore-backups do not list implied entries ending with ~
-c with -lt: sort by, and show, ctime (time of last
modification of file status information);
with -l: show ctime and sort by name;
otherwise: sort by ctime, newest first
-C list entries by columns
--color[=WHEN] colorize the output; WHEN can be 'always' (default
if omitted), 'auto', or 'never'; more info below
-d, --directory list directories themselves, not their contents
-D, --dired generate output designed for Emacs' dired mode
-f do not sort, enable -aU, disable -ls --color
-F, --classify append indicator (one of */=>@|) to entries
... ... ...
Quando usare le opzioni brevi o lunghe
Quando le opzioni esistono sia come opzioni brevi che lunghe:
- Usare l’opzione breve quando si digitano comandi direttamente nella shell per ridurre al minimo la pressione dei tasti e svolgere più rapidamente il proprio compito.
- Usate l’opzione long negli script per fornire chiarezza. Verrà letto molte volte e digitato una sola volta.
Il comando man
L’altro modo per conoscere ls è digitare
Questo comando trasformerà il vostro terminale in una pagina con una
descrizione del comando ls e delle sue opzioni.
Per navigare tra le pagine di man, si possono usare
↑ e ↓ per spostarsi riga per riga, oppure provare
b e Spacebar per saltare su e giù di una pagina
intera. Per cercare un carattere o una parola nelle pagine di
man, usare / seguito dal carattere o dalla
parola che si sta cercando. A volte una ricerca produce più risultati.
In tal caso, è possibile spostarsi tra i risultati utilizzando
N (per andare avanti) e Shift+N (per
andare indietro).
Per uscire dalle pagine man, premere q.
Pagine di manuale sul web
Naturalmente, esiste un terzo modo per accedere alla guida dei
comandi: la ricerca su Internet tramite il browser. Quando si utilizza
la ricerca su Internet, includere la frase unix man page
nella query di ricerca aiuterà a trovare risultati pertinenti.
GNU fornisce collegamenti ai suoi manuali, compreso il core GNU utilities, che copre molti comandi introdotti in questa lezione.
Esplorazione di altre opzioni
ls
È anche possibile utilizzare due opzioni contemporaneamente. Cosa fa
il comando ls quando viene usato con l’opzione
-l? E se si utilizzano sia l’opzione -l che
l’opzione -h?
Alcuni dei suoi risultati riguardano proprietà che non vengono trattate in questa lezione (come i permessi e la proprietà dei file), ma il resto dovrebbe essere comunque utile.
L’opzione -l fa sì che ls utilizzi un
formato di elenco llungo, mostrando non solo i nomi dei
file/directory ma anche informazioni aggiuntive, come la dimensione del
file e l’ora dell’ultima modifica. Se si usano sia l’opzione
-h che l’opzione -l, si rende la dimensione
del file “leggibile dall’uomo”, cioè si visualizza qualcosa come
5.3K invece di 5369.
Elenco in ordine cronologico inverso
Per impostazione predefinita, ls elenca il contenuto di
una cartella in ordine alfabetico per nome. Il comando
ls -t elenca gli elementi in base all’ora dell’ultima
modifica invece che in ordine alfabetico. Il comando ls -r
elenca il contenuto di una cartella in ordine inverso. Quale file viene
visualizzato per ultimo quando si combinano le opzioni -t e
-r? Suggerimento: Potrebbe essere necessario usare
l’opzione -l per vedere le ultime date di modifica.
Il file modificato più di recente è elencato per ultimo quando si usa
-rt. Questo può essere molto utile per trovare le modifiche
più recenti o per verificare se è stato scritto un nuovo file di
output.
Esplorazione di altre cartelle
Non solo si può usare ls sulla cartella di lavoro
corrente, ma anche per elencare il contenuto di una cartella diversa.
Diamo un’occhiata alla nostra cartella Desktop eseguendo
ls -F Desktop, cioè il comando ls con la
opzione -F e
l’[argomento][Argomenti] Desktop.
L’argomento Desktop indica a ls che si vuole
un elenco di qualcosa di diverso dalla cartella di lavoro corrente:
OUTPUT
shell-lesson-data/
Si noti che se una cartella denominata Desktop non
esiste nella cartella di lavoro corrente, questo comando restituirà un
errore. In genere, una cartella Desktop esiste nella
propria home directory, che si presume sia la cartella di lavoro
corrente della shell bash.
L’output dovrebbe essere un elenco di tutti i file e le sottocartelle
della vostra cartella Desktop, compresa la cartella
shell-lesson-data che avete scaricato nel setup per questa lezione. (Nella maggior parte dei
sistemi, il contenuto della cartella Desktop nella shell
viene visualizzato come icona in un’interfaccia grafica dietro tutte le
finestre aperte. Verificate se questo è il vostro caso)
Organizzare le cose in modo gerarchico ci aiuta a tenere traccia del nostro lavoro. Sebbene sia possibile mettere centinaia di file nella nostra cartella home, così come è possibile ammassare centinaia di fogli stampati sulla nostra scrivania, è molto più facile trovare le cose quando sono organizzate in sottocartelle con nomi ragionevoli.
Ora che sappiamo che la cartella shell-lesson-data si
trova nella nostra cartella Desktop, possiamo fare due cose.
Per prima cosa, usando la stessa strategia di prima, possiamo
esaminare il suo contenuto passando il nome di una cartella a
ls:
OUTPUT
exercise-data/ north-pacific-gyre/
In secondo luogo, possiamo cambiare la nostra posizione in una cartella diversa, in modo da non trovarci più nella nostra cartella home.
Il comando per cambiare posizione è cd seguito da un
nome di cartella per cambiare la nostra cartella di lavoro.
cd sta per ‘change directory’, il che è un po’ fuorviante.
Il comando non cambia la cartella, ma la cartella di lavoro corrente
della shell. In altre parole, cambia le impostazioni della shell per
quanto riguarda la cartella in cui ci troviamo. Il comando
cd è simile a un doppio clic su una cartella in
un’interfaccia grafica per entrare in quella cartella.
Supponiamo di volerci spostare nella cartella
exercise-data che abbiamo visto sopra. Per arrivarci
possiamo usare la seguente serie di comandi:
Questi comandi ci spostano dalla nostra cartella home alla nostra
cartella Desktop, poi alla cartella shell-lesson-data,
quindi alla directory exercise-data. Si noterà che
cd non stampa nulla. Questo è normale. Molti comandi di
shell non producono nulla sullo schermo quando vengono eseguiti con
successo. Ma se si esegue pwd dopo di esso, si può vedere
che ora ci troviamo in
/Users/nelle/Desktop/shell-lesson-data/exercise-data.
Se ora si esegue ls -F senza argomenti, viene elencato
il contenuto di
/Users/nelle/Desktop/shell-lesson-data/exercise-data,
perché è lì che ci troviamo:
OUTPUT
/Users/nelle/Desktop/shell-lesson-data/exercise-data
OUTPUT
alkanes/ animal-counts/ creatures/ numbers.txt writing/
Ora sappiamo come scendere nell’albero delle cartelle (cioè come entrare in una sottocartella), ma come salire (cioè come lasciare una cartella e andare nella sua cartella home)? Potremmo provare a fare come segue:
ERRORE
-bash: cd: shell-lesson-data: No such file or directory
ma si ottiene un errore! Perché?
Con i metodi utilizzati finora, cd può vedere solo le
sottocartelle all’interno della cartella corrente. Esistono diversi modi
per vedere le cartella al di sopra della posizione corrente; inizieremo
con il più semplice.
Esiste una scorciatoia nella shell per spostarsi su un livello di cartella. Funziona come segue:
.. è un nome speciale di cartella che significa “la
cartella che contiene questa”, o più brevemente, il
genitore della cartella corrente. Sicuramente, se si
esegue pwd dopo aver eseguito cd .., ci si
ritrova in /Users/nelle/Desktop/shell-lesson-data:
OUTPUT
/Users/nelle/Desktop/shell-lesson-data
La cartella speciale .. di solito non viene visualizzata
quando si esegue ls. Se si desidera visualizzarla, si può
aggiungere l’opzione -a a ls -F:
OUTPUT
./ ../ exercise-data/ north-pacific-gyre/
-a sta per “mostra tutto” (compresi i file nascosti);
obbliga ls a mostrare i nomi dei file e delle cartella che
iniziano con ., come ad esempio .. (che, se ci
troviamo in /Users/nelle, si riferisce alla cartella
/Users). Come si può vedere, viene visualizzata anche
un’altra cartella speciale, chiamata ., che significa “la
cartella di lavoro corrente”. Può sembrare superfluo avere un nome per
questa cartella, ma presto ne vedremo l’uso.
Si noti che nella maggior parte degli strumenti a riga di comando,
più opzioni possono essere combinate con un singolo - e
senza spazi tra le opzioni; ls -F -a è equivalente a
ls -Fa.
Altri file nascosti
Oltre alle cartella nascoste .. e ., è
possibile che venga visualizzato anche un file chiamato
.bash_profile. Questo file contiene solitamente le
impostazioni di configurazione della shell. Si possono vedere anche
altri file e cartella che iniziano con .. Si tratta in
genere di file e cartella utilizzati per configurare diversi programmi
sul computer. Il prefisso . è usato per evitare che questi
file di configurazione ingombrino il terminale quando si usa il comando
standard ls.
Questi tre comandi sono i comandi di base per navigare nel filesystem
del computer: pwd, ls e cd.
Esploriamo alcune variazioni di questi comandi. Cosa succede se si
digita cd da solo, senza indicare una directory?
Come si può controllare cosa è successo? pwd ci dà la
risposta!
OUTPUT
/Users/nelle
Si scopre che cd senza un argomento vi riporterà alla
vostra cartella home, il che è ottimo se vi siete persi nel vostro
filesystem.
Proviamo a tornare alla cartella exercise-data di prima.
L’ultima volta abbiamo usato tre comandi, ma possiamo mettere insieme
l’elenco delle cartella per spostarci a exercise-data in un
solo passaggio:
Verificare che ci si sia spostati nel posto giusto eseguendo
pwd e ls -F.
Se si vuole salire di un livello dalla cartella dei dati, si può
usare cd ... Ma c’è un altro modo per spostarsi in
qualsiasi cartella, indipendentemente dalla posizione attuale.
Finora, quando si sono specificati i nomi delle cartella, o anche un
percorso di cartella (come sopra), si sono usati percorsi
relativi. Quando si usa un percorso relativo con un comando
come ls o cd, si cerca di trovare quella
posizione dal punto in cui ci si trova, piuttosto che dalla radice del
file system.
Tuttavia, è possibile specificare il percorso
assoluto di una cartella includendo il suo intero percorso a
partire dalla cartella principale, indicata da una barra iniziale. La
barra iniziale / indica al computer di seguire il percorso
dalla radice del file system, in modo da riferirsi sempre esattamente a
una cartella, indipendentemente dalla posizione in cui ci si trova
quando si esegue il comando.
Questo ci permette di spostarci nella nostra cartella
shell-lesson-data da qualsiasi punto del filesystem (anche
da dentro exercise-data). Per trovare il percorso assoluto
che stiamo cercando, possiamo usare pwd e poi estrarre il
pezzo che dobbiamo spostare in shell-lesson-data.
OUTPUT
/Users/nelle/Desktop/shell-lesson-data/exercise-data
Eseguire pwd e ls -F per assicurarsi di
essere nella directory prevista.
Altre due scorciatoie
La shell interpreta il carattere tilde (~) all’inizio di
un percorso come “la cartella home dell’utente corrente”. Ad esempio, se
la cartella home di Nelle è /Users/nelle, allora
~/data è equivalente a /Users/nelle/data.
Questo funziona solo se è il primo carattere del percorso;
here/there/~/elsewhere è non
here/there/Users/nelle/elsewhere.
Un’altra scorciatoia è il carattere -
(trattino).cd tradurrà - in la cartella
precedente in cui mi trovavo, il che è più veloce che dover
ricordare, e poi digitare, il percorso completo. Questo è un modo
molto efficiente di spostarsi avanti e indietro tra due
cartella – cioè se si esegue cd - due volte, si torna
alla cartella di partenza.
La differenza tra cd .. e cd - è che il
primo porta su, mentre il secondo porta indietro.
Provate! Per prima cosa spostatevi in
~/Desktop/shell-lesson-data (dovreste essere già lì).
Poi cd nella cartella
exercise-data/creatures
ora se si esegue
vedrete che siete tornati in
~/Desktop/shell-lesson-data. Eseguite di nuovo
cd - e sarete di nuovo in
~/Desktop/shell-lesson-data/exercise-data/creatures
Percorsi assoluti e relativi
Partendo da /Users/nelle/data, quale dei seguenti
comandi potrebbe essere usato da Nelle per navigare verso la sua
cartella home, che è /Users/nelle?
cd .cd /cd /home/nellecd ../..cd ~cd homecd ~/data/..cdcd ..
- No:
.sta per la cartella corrente. - No:
/sta per la cartella principale. - No: la cartella home di Nelle è
/Users/nelle. - No: questo comando sale di due livelli, cioè termina con
/Users. - Sì:
~sta per la cartella home dell’utente, in questo caso/Users/nelle. - No: questo comando naviga in una cartella
homenella cartella corrente, se esiste. - Sì: inutilmente complicato, ma corretto.
- Sì: scorciatoia per tornare alla cartella principale dell’utente.
- Sì: sale di un livello.
Risoluzione del percorso relativo
Utilizzando il diagramma del filesystem qui sotto, se
pwd visualizza /Users/thing, cosa visualizzerà
ls -F ../backup?
../backup: No such file or directory2012-12-01 2013-01-08 2013-01-272012-12-01/ 2013-01-08/ 2013-01-27/original/ pnas_final/ pnas_sub/
- No: c’è *una cartella
backupin/Users. - No: questo è il contenuto di
Users/thing/backup, ma con.., abbiamo chiesto un livello più in alto. - No: vedi spiegazione precedente.
- Sì:
../backup/si riferisce a/Users/backup/.
ls Comprensione della
lettura
Utilizzando il diagramma del filesystem qui sotto, se
pwd visualizza /Users/backup e -r
dice a ls di visualizzare le cose in ordine inverso,
quale/i comando/i produrrà il seguente output:
OUTPUT
pnas_sub/ pnas_final/ original/
ls pwdls -r -Fls -r -F /Users/backup
- No:
pwdnon è il nome di una cartella. - Sì:
lssenza l’argomento cartella elenca i file e le directory nella directory corrente. - Sì: utilizza esplicitamente il percorso assoluto.
Sintassi generale di un comando di Shell
Abbiamo già incontrato comandi, opzioni e argomenti, ma forse è utile formalizzare un po’ di terminologia.
Considerate il comando qui sotto come un esempio generale di comando, che verrà sezionato nelle sue parti componenti:
ls è il comando, con una
opzione -F e un argomento
/. Abbiamo già incontrato opzioni che iniziano con un solo
trattino (-), note come opzioni corte, o
con due trattini (--), note come opzioni
lunghe. le [Opzioni] modificano il comportamento di un comando
e gli [Argomenti] indicano al comando su cosa operare (ad esempio, file
e cartella). A volte le opzioni e gli argomenti sono indicati come
parametri. Un comando può essere chiamato con più di
un’opzione e più di un argomento, ma non sempre un comando richiede un
argomento o un’opzione.
A volte si può vedere che le opzioni vengono chiamate scambi o flags, specialmente per le opzioni che non richiedono argomenti. In questa lezione useremo il termine opzione.
Ogni parte è separata da spazi. Se si omette lo spazio tra
ls e -F la shell cercherà un comando chiamato
ls-F, che non esiste. Inoltre, la capitalizzazione può
essere importante. Ad esempio, ls -s visualizzerà la
dimensione dei file e delle cartella accanto ai nomi, mentre
ls -S ordinerà i file e le cartella per dimensione, come
mostrato di seguito:
OUTPUT
total 28
4 animal-counts 4 creatures 12 numbers.txt 4 alkanes 4 writing
Si noti che le dimensioni restituite da ls -s sono in
blocchi. Poiché queste sono definite in modo diverso per i
diversi sistemi operativi, è possibile che non si ottengano le stesse
cifre dell’esempio.
OUTPUT
animal-counts creatures alkanes writing numbers.txt
Mettendo insieme tutti questi elementi, il comando
ls -F / di cui sopra fornisce un elenco di file e cartella
nella cartella principale /. Di seguito è riportato un
esempio dell’output che si potrebbe ottenere dal comando precedente:
OUTPUT
Applications/ System/
Library/ Users/
Network/ Volumes/
Pipeline di Nelle: Organizzare i file
sapendo queste informazioni su file e cartella, Nelle è pronta a organizzare i file che la macchina per il saggio delle proteine creerà.
Crea una cartella chiamata north-pacific-gyre (per
ricordarsi da dove provengono i dati), che conterrà i file di dati della
macchina di analisi e i suoi script di elaborazione dei dati.
Ogni campione fisico è etichettato secondo la convenzione del suo
laboratorio con un ID unico di dieci caratteri, ad esempio “NENE01729A”.
Questo ID viene utilizzato nel registro di raccolta per registrare la
posizione, l’ora, la profondità e altre caratteristiche del campione,
quindi decide di utilizzarlo nel nome di ogni file di dati. Poiché
l’output della macchina di analisi è un testo semplice, chiamerà i suoi
file NENE01729A.txt, NENE01812A.txt e così
via. Tutti i 1520 file andranno nella stessa directory.
Ora nella sua cartella corrente shell-lesson-data, Nelle
può vedere quali file ha usando il comando:
Questo comando è molto impegnativo da digitare, ma si può lasciare che la shell faccia la maggior parte del lavoro attraverso il cosiddetto completamento delle tabelle. Se si digita:
e poi preme Tab (il tasto tab della tastiera), la shell completa automaticamente il nome della cartella:
Premendo di nuovo Tab non si ottiene nulla, poiché ci sono più possibilità; premendo Tab due volte si ottiene un elenco di tutti i file.
Se Nelle preme G e poi di nuovo Tab, la shell aggiungerà ‘goo’ poiché tutti i file che iniziano con ‘g’ condividono i primi tre caratteri ‘goo’.
per vedere tutti quei file, si può premere Tab altre due volte.
questo si chiama completamento delle tabelle e lo vedremo in molti altri strumenti man mano che andremo avanti.
- Il file system è responsabile della gestione delle informazioni sul disco.
- Le informazioni sono memorizzate in file, che sono memorizzati in cartelle.
- le cartelle possono anche memorizzare altre cartelle, che formano un albero di cartelle.
-
pwdstampa la cartella di lavoro corrente dell’utente. -
ls [path]stampa un elenco di uno specifico file o cartella;lsda solo elenca la cartella di lavoro corrente. -
cd [path]cambia la cartella di lavoro corrente. - La maggior parte dei comandi accetta opzioni che iniziano con un
singolo
-. - i nomi delle cartelle in un percorso sono separati con
/su Unix, ma\su Windows. -
/da sola è la cartella principale dell’intero file system. - Un percorso assoluto specifica una posizione dalla radice del file system.
- Un percorso relativo specifica una posizione a partire da quella corrente.
-
.da solo significa “la cartella corrente”;..significa “la cartella sopra quella corrente”.
Content from Lavorare con i file e le directory
Ultimo aggiornamento il 2025-11-07 | Modifica questa pagina
Tempo stimato: 50 minuti
Panoramica
Domande
- Come posso creare, copiare ed eliminare file e cartelle?
- Come posso modificare i file?
Obiettivi
- Eliminare, copiare e spostare file e/o cartelle.
- Creare i file in questa gerarchia usando un editor o copiando e rinominando i file esistenti.
- Creare una gerarchia di cartelle che corrisponda a un diagramma dato.
Creazione di directory
Ora sappiamo come esplorare i file e le cartelle, ma come crearli?
In questo episodio impareremo a creare e spostare file e directory,
utilizzando come esempio la cartella
exercise-data/writing.
Fase uno: vedere dove siamo e cosa abbiamo già
Dovremmo ancora trovarci nella cartella
shell-lesson-data sul Desktop, che possiamo controllare
usando:
OUTPUT
/Users/nelle/Desktop/shell-lesson-data
Ora ci sposteremo nella cartella exercise-data/writing e
vedremo cosa contiene:
OUTPUT
haiku.txt LittleWomen.txt
Creare una cartella
Creiamo una nuova cartella chiamata thesis usando il
comando mkdir thesis (che non ha output):
Come si può intuire dal nome, mkdir significa “directory
make”. Poiché thesis è un percorso relativo (cioè non ha
una barra iniziale, come /what/ever/thesis), la nuova
cartella viene creata nella cartella di lavoro corrente:
OUTPUT
haiku.txt LittleWomen.txt thesis/
Dato che abbiamo appena creato la cartella thesis, non
c’è ancora nulla al suo interno:
Si noti che mkdir non si limita a creare singole
cartelle una alla volta. L’opzione -p permette a
mkdir di creare una cartella con sottocartelle annidate in
una singola operazione:
L’opzione -R del comando ls elenca tutte le
sottocartelle annidate all’interno di una cartella. Usiamo
ls -FR per elencare ricorsivamente la nuova gerarchia di
cartelle appena creata nella cartella project:
OUTPUT
../project/:
data/ results/
../project/data:
../project/results:
Due modi di fare la stessa cosa
l’uso della shell per creare una cartella non è diverso dall’uso di
un file explorer. Se si apre la cartella corrente utilizzando il file
explorer grafico del sistema operativo, la cartella thesis
apparirà anche lì. Mentre la shell e il file explorer sono due modi
diversi di interagire con i file, i file e le cartelle sono gli
stessi.
Buoni nomi per i file e le directory
I nomi complicati di file e cartelle possono rendere la vita difficile quando si lavora alla riga di comando. Qui forniamo alcuni suggerimenti utili per i nomi dei file e delle cartelle.
- Non usare spazi.
Gli spazi possono rendere un nome più significativo, ma poiché gli
spazi sono usati per separare gli argomenti sulla riga di comando, è
meglio evitarli nei nomi di file e directory. Al loro posto si può usare
- o _ (ad esempio
north-pacific-gyre/ piuttosto che
north pacific gyre/). Per verificarlo, provare a digitare
mkdir north pacific gyre e vedere quale directory (o
directory!) viene creata quando si controlla con ls -F.
- Non iniziare il nome con
-(trattino).
I comandi trattano i nomi che iniziano con - come
opzioni.
- attenersi a lettere, numeri,
.(punto o ‘stop completo’),-(trattino) e_(trattino basso).
Molti altri caratteri hanno un significato speciale sulla riga di comando. Ne conosceremo alcuni nel corso di questa lezione. Ci sono caratteri speciali che possono far sì che il vostro comando non funzioni come previsto e possono persino causare la perdita di dati.
Se è necessario fare riferimento a nomi di file o cartelle che
contengono spazi o altri caratteri speciali, è necessario circondare il
nome con [virgolette] singole (https://www.gnu.org/software/bash/manual/html_node/Quoting.html)
('').
Gli studenti possono talvolta rimanere intrappolati in editor di testo a riga di comando come Vim, Emacs o Nano. Chiudere l’emulatore di terminale e aprirne uno nuovo può essere frustrante, perché gli studenti devono navigare di nuovo nella cartella corretta. La nostra raccomandazione per attenuare questo problema è che gli istruttori usino lo stesso editor di testo degli studenti durante i workshop (nella maggior parte dei casi Nano).
Creare un file di testo
Cambiamo la nostra cartella di lavoro in thesis usando
cd, quindi eseguiamo un editor di testo chiamato Nano per
creare un file chiamato draft.txt:
Quale editor?
Quando diciamo che “nano è un editor di testo”
intendiamo proprio “testo”. Può lavorare solo con i dati a caratteri
semplici, non con tabelle, immagini o altri supporti di facile utilizzo.
Lo usiamo negli esempi perché è uno degli editor di testo meno
complessi. Tuttavia, a causa di questa caratteristica, potrebbe non
essere abbastanza potente o flessibile per il lavoro che dovrete
svolgere dopo questo workshop. Sui sistemi Unix (come Linux e macOS),
molti programmatori usano Emacs o Vim (entrambi richiedono più tempo per
essere appresi), oppure un editor grafico come Gedit o VScode. Su Windows, si può
usare Notepad++. Windows ha
anche un editor incorporato chiamato notepad che può essere
eseguito dalla riga di comando allo stesso modo di nano per
gli scopi di questa lezione.
Indipendentemente dall’editor utilizzato, è necessario sapere dove cerca e salva i file. Se lo si avvia dalla shell, (probabilmente) userà la cartella di lavoro corrente come posizione predefinita. Se si utilizza il menu di avvio del computer, potrebbe voler salvare i file nella cartella Desktop o Documenti. È possibile cambiare questa scelta navigando in un’altra cartella la prima volta che si fa “Salva con nome…”
digitiamo alcune righe di testo.

Una volta che siamo soddisfatti del nostro testo, possiamo premere
Ctrl+O (premere il tasto Ctrl o
Control e, tenendolo premuto, premere il tasto O)
per scrivere i nostri dati su disco. Verrà richiesto un nome per il file
che conterrà il testo. Premete Retro per accettare il nome
predefinito suggerito di draft.txt.
una volta salvato il nostro file, possiamo usare Ctrl+X per uscire dall’editor e tornare alla shell.
Tasto Control, Ctrl o ^
Il tasto Control è anche chiamato “Ctrl”. L’uso del tasto Control può essere descritto in vari modi. Ad esempio, si può vedere l’istruzione di premere il tasto Control e, tenendolo premuto, premere il tasto X, descritto come uno dei seguenti:
Control-XControl+XCtrl-XCtrl+X^XC-x
In nano, nella parte inferiore dello schermo si vedrà
^G Get Help ^O WriteOut. Ciò significa che si può usare
Control-G per ottenere aiuto e Control-O per
salvare il file.
nano non lascia alcun output sullo schermo dopo la sua
uscita, ma ls ora mostra che è stato creato un file
chiamato draft.txt:
OUTPUT
draft.txt
Creare file in modo diverso
Abbiamo visto come creare file di testo usando l’editor
nano. Ora provate il seguente comando:
Cosa ha fatto il comando
touch? Quando si guarda alla cartella corrente usando l’esploratore di file della GUI, il file appare?Utilizzare
ls -lper ispezionare i file. Quanto è grandemy_file.txt?Quando si potrebbe voler creare un file in questo modo?
Il comando
touchgenera un nuovo file chiamatomy_file.txtnella cartella corrente. È possibile osservare questo nuovo file generato digitandolsal prompt della riga di comando. il filemy_file.txtpuò anche essere visualizzato nel file explorer della GUI.Quando si ispeziona il file con
ls -l, si noti che la dimensione dimy_file.txtè di 0 byte. In altre parole, non contiene dati. Se si apremy_file.txtcon il proprio editor di testo, è vuoto.Alcuni programmi non generano direttamente i file di output, ma richiedono che siano già stati generati dei file vuoti. Quando il programma viene eseguito, cerca un file esistente da riempire con il suo output. Il comando touch consente di generare in modo efficiente un file di testo vuoto da utilizzare per tali programmi.
Creare file in modo diverso (continued)
Cosa c’è in un nome?
Avrete notato che tutti i file di Nelle si chiamano “qualcosa punto
qualcosa”, e in questa parte della lezione abbiamo sempre usato
l’estensione .txt. Questa è solo una convenzione; possiamo
chiamare un file mythesis o qualsiasi altra cosa vogliamo.
Tuttavia, la maggior parte delle persone usa nomi divisi in due parti
per aiutare loro (e i loro programmi) a distinguere i diversi tipi di
file. La seconda parte del nome è chiamata estensione del nome
del file e indica il tipo di dati contenuti nel file:
.txt segnala un file di testo semplice, .pdf
indica un documento PDF, .cfg è un file di configurazione
pieno di parametri per qualche programma o altro, .png è
un’immagine PNG e così via.
Questa è solo una convenzione, anche se importante. I file contengono semplicemente dei byte; sta a noi e ai nostri programmi interpretarli secondo le regole dei file di testo, dei documenti PDF, dei file di configurazione, delle immagini e così via.
Nominare un’immagine PNG di una balena come whale.mp3
non la trasforma magicamente in una registrazione di un canto di balena,
anche se potrebbe far sì che il sistema operativo associ il
file a un programma di riproduzione musicale. In questo caso, se
qualcuno fa doppio clic su whale.mp3 in un programma di
esplorazione file, il lettore musicale tenterà automaticamente (ed
erroneamente) di aprire il file whale.mp3.
Spostamento di file e directory
Ritorno alla cartella
shell-lesson-data/exercise-data/writing,
Nella nostra cartella thesis abbiamo un file
draft.txt che non è un nome particolarmente informativo,
quindi cambiamo il nome del file usando mv, che è
l’abbreviazione di ‘move’:
Il primo argomento dice a mv che cosa stiamo
‘spostando’, mentre il secondo è dove deve andare. In questo caso,
stiamo spostando thesis/draft.txt in
thesis/quotes.txt, il che ha lo stesso effetto di
rinominare il file. Sicuramente, ls ci mostra che
thesis ora contiene un file chiamato
quotes.txt:
OUTPUT
quotes.txt
È necessario prestare attenzione quando si specifica il nome del file
di destinazione, poiché mv sovrascriverà silenziosamente
qualsiasi file esistente con lo stesso nome, con conseguente perdita di
dati. Per impostazione predefinita, mv non chiede conferma
prima di sovrascrivere i file. Tuttavia, un’opzione aggiuntiva,
mv -i (o mv --interactive), farà sì che
mv richieda tale conferma.
Si noti che mv funziona anche sulle cartelle.
Spostiamo quotes.txt nella cartella di lavoro corrente.
Usiamo ancora una volta mv, ma questa volta useremo solo il
nome di una cartella come secondo argomento per dire a mv
che vogliamo mantenere il nome del file ma metterlo in un posto nuovo.
(In questo caso, il nome della cartella che utilizziamo è il nome
speciale della cartella . di cui abbiamo parlato in
precedenza.
L’effetto è quello di spostare il file dalla cartella in cui si
trovava alla cartella di lavoro corrente. ls ora mostra che
thesis è vuoto:
OUTPUT
$
In alternativa, possiamo confermare che il file
quotes.txt non è più presente nella cartella
thesis provando esplicitamente a elencarlo:
ERRORE
ls: cannot access 'thesis/quotes.txt': No such file or directory
ls con un nome di file o una cartella come argomento
elenca solo il file o la cartella richiesti. Se il file dato come
argomento non esiste, la shell restituisce un errore come abbiamo visto
sopra. Possiamo usare questa funzione per vedere che
quotes.txt è ora presente nella nostra cartella
corrente:
OUTPUT
quotes.txt
Spostamento dei file in una nuova cartella
Dopo aver eseguito i seguenti comandi, Jamie si rende conto di aver
inserito i file sucrose.dat e maltose.dat
nella cartella sbagliata. I file avrebbero dovuto essere inseriti nella
cartella raw.
BASH
$ ls -F
analyzed/ raw/
$ ls -F analyzed
fructose.dat glucose.dat maltose.dat sucrose.dat
$ cd analyzed
riempire gli spazi vuoti per spostare questi file nella cartella
raw/ (cioè quella in cui si è dimenticato di metterli)
Copia di file e directory
Il comando cp funziona in modo molto simile a
mv, solo che copia un file invece di spostarlo. Possiamo
verificare che abbia fatto la cosa giusta usando ls con due
percorsi come argomenti — come la maggior parte dei comandi Unix, a
ls possono essere dati più percorsi contemporaneamente:
OUTPUT
quotes.txt thesis/quotations.txt
Possiamo anche copiare una cartella e tutto il suo contenuto usando
l’opzione recursive
-r, ad esempio per fare il backup di una cartella:
Possiamo verificare il risultato elencando il contenuto di entrambe
le cartelle thesis e thesis_backup:
OUTPUT
thesis:
quotations.txt
thesis_backup:
quotations.txt
È importante includere il flag -r. Se si vuole copiare
una cartella e si omette questa opzione, verrà visualizzato un messaggio
che indica che la cartella è stata omessa perché
-r not specified.
Rinominare i file
Supponiamo di aver creato un file di testo semplice nella nostra
cartella corrente per contenere un elenco dei test statistici che
dovremo fare per analizzare i nostri dati, e di averlo chiamato
statstics.txt
Dopo aver creato e salvato questo file ci si accorge di aver sbagliato il nome del file! Per correggere l’errore, quale dei seguenti comandi si può utilizzare?
cp statstics.txt statistics.txtmv statstics.txt statistics.txtmv statstics.txt .cp statstics.txt .
- No. Sebbene questa operazione crei un file con il nome corretto, il file con il nome sbagliato esiste ancora nella cartella e deve essere cancellato.
- Sì, questo funzionerebbe per rinominare il file.
- No, il punto(.) indica dove spostare il file, ma non fornisce un nuovo nome di file; non è possibile creare nomi di file identici.
- No, il punto(.) indica dove copiare il file, ma non fornisce un nuovo nome di file; non è possibile creare nomi di file identici.
Spostare e copiare
Qual è l’output del comando di chiusura ls nella
sequenza mostrata sotto?
OUTPUT
/Users/jamie/data
OUTPUT
proteins.dat
BASH
$ mkdir recombined
$ mv proteins.dat recombined/
$ cp recombined/proteins.dat ../proteins-saved.dat
$ ls
proteins-saved.dat recombinedrecombinedproteins.dat recombinedproteins-saved.dat
Partiamo dalla cartella /Users/jamie/data e creiamo una
nuova cartella chiamata recombined. La seconda riga sposta
(mv) il file proteins.dat nella nuova cartella
(recombined). La terza riga crea una copia del file appena
spostato. La parte difficile è dove il file è stato copiato. Ricordiamo
che .. significa “salire di livello”, quindi il file
copiato si trova ora in /Users/jamie. Si noti che
.. è interpretato rispetto alla cartella di lavoro
corrente, non rispetto alla posizione del file copiato.
Quindi, l’unica cosa che verrà mostrata usando ls (in
/Users/jamie/data) è la cartella ricombinata.
- No, vedi spiegazione sopra.
proteins-saved.datsi trova in/Users/jamie - Si
- No, vedi spiegazione sopra.
proteins.datsi trova in/Users/jamie/data/recombined - No, vedi spiegazione sopra.
proteins-saved.datsi trova in/Users/jamie
Rimozione di file e cartella
Tornando alla cartella
shell-lesson-data/exercise-data/writing, riordiniamola
rimuovendo il file quotes.txt che abbiamo creato. Il
comando Unix che useremo a questo scopo è rm (abbreviazione
di ‘remove’):
Possiamo confermare che il file è andato via usando
ls:
ERRORE
ls: cannot access 'quotes.txt': No such file or directory
L’eliminazione è per sempre
La shell di Unix non ha un cestino da cui recuperare i file cancellati (anche se la maggior parte delle interfacce grafiche di Unix ce l’ha). Invece, quando si cancellano i file, questi vengono scollegati dal file system in modo che il loro spazio di archiviazione sul disco possa essere riciclato. Esistono strumenti per trovare e recuperare i file cancellati, ma non è detto che funzionino in una particolare situazione, poiché il computer potrebbe riciclare subito lo spazio su disco del file.
Usare rm in modo sicuro
Cosa succede quando si esegue
rm -i thesis_backup/quotations.txt? Perché si vuole questa
protezione quando si usa rm?
OUTPUT
rm: remove regular file 'thesis_backup/quotations.txt'? y
L’opzione -i chiederà prima di (ogni) rimozione (usare
Y per confermare la cancellazione o N per
mantenere il file). La shell Unix non ha un cestino, quindi tutti i file
rimossi spariranno per sempre. Utilizzando l’opzione -i, si
ha la possibilità di verificare che si stiano eliminando solo i file che
si desidera rimuovere.
Se si tenta di rimuovere la cartella thesis usando
rm thesis, si ottiene un messaggio di errore:
ERRORE
rm: cannot remove 'thesis': Is a directory
Questo accade perché rm per impostazione predefinita
funziona solo sui file, non sulle cartelle.
rm può rimuovere una cartella e tutto il suo
contenuto se si usa l’opzione ricorsiva -r, e lo farà
senza alcuna richiesta di conferma:
Dato che non c’è modo di recuperare i file cancellati usando la
shell, rm -r dovrebbe essere usato con grande
cautela (si potrebbe considerare di aggiungere l’opzione
interattiva rm -r -i).
Operazioni con più file e cartelle
Spesso è necessario copiare o spostare più file contemporaneamente. Questo può essere fatto fornendo un elenco di singoli nomi di file o specificando un modello di denominazione utilizzando i caratteri jolly. I caratteri jolly sono caratteri speciali che possono essere utilizzati per rappresentare caratteri sconosciuti o insiemi di caratteri durante la navigazione nel file system Unix.
Copia con più nomi di file
Per questo esercizio, è possibile provare i comandi nella cartella
shell-lesson-data/exercise-data.
Nell’esempio seguente, cosa fa cp quando gli vengono
dati diversi nomi di file e un nome di cartella?
Nell’esempio seguente, cosa fa cp quando gli vengono
dati tre o più nomi di file?
OUTPUT
basilisk.dat minotaur.dat unicorn.dat
Se viene dato più di un nome di file seguito da un nome di cartella
(cioè la cartella di destinazione deve essere l’ultimo argomento),
cp copia i file nella cartella nominata.
Se vengono dati tre nomi di file, cp lancia un errore
come quello che segue, perché si aspetta il nome di una cartella come
ultimo argomento.
ERRORE
cp: target 'basilisk.dat' is not a directory
Uso dei caratteri jolly per accedere a più file contemporaneamente
Caratteri jolly
* è un wildcard, che rappresenta zero o
più altri caratteri. Consideriamo la cartella
shell-lesson-data/exercise-data/alkanes: *.pdb
rappresenta ethane.pdb, propane.pdb e ogni
file che termina con ‘.pdb’. D’altra parte, p*.pdb
rappresenta solo pentane.pdb e propane.pdb,
perché la ‘p’ all’inizio può rappresentare solo nomi di file che
iniziano con la lettera ‘p’.
Anche ? è un carattere jolly, ma rappresenta esattamente
un carattere. Quindi ?ethane.pdb potrebbe rappresentare
methane.pdb mentre *ethane.pdb rappresenta sia
ethane.pdb che methane.pdb.
I caratteri jolly possono essere usati in combinazione tra loro. Ad
esempio, ???ane.pdb indica tre caratteri seguiti da
ane.pdb, che danno
cubane.pdb ethane.pdb octane.pdb.
Quando la shell vede un carattere jolly, lo espande per creare un
elenco di nomi di file corrispondenti prima di eseguire il
comando precedente. Come eccezione, se un’espressione con il carattere
jolly non corrisponde a nessun file, Bash passerà l’espressione come
argomento al comando così com’è. Per esempio, digitando
ls *.pdf nella cartella alkanes (che contiene
solo file con nomi che terminano con .pdb) si ottiene un
messaggio di errore che indica che non esiste un file chiamato
*.pdf. Tuttavia, generalmente comandi come wc
e ls vedono gli elenchi di nomi di file che corrispondono a
queste espressioni, ma non i caratteri jolly stessi. È la shell, non gli
altri programmi, a espandere i caratteri jolly.
Elenca i nomi dei file che corrispondono a uno schema
Quando vengono eseguiti nella cartella alkanes, quali
comandi ls produrranno questo output?
ethane.pdb methane.pdb
ls *t*ane.pdbls *t?ne.*ls *t??ne.pdbls ethane.*
La soluzione è 3.
1. mostra tutti i file il cui nome contiene zero o più
caratteri (*) seguiti dalla lettera t, poi
zero o più caratteri (*) seguiti da ane.pdb.
Si ottiene così
ethane.pdb methane.pdb octane.pdb pentane.pdb.
2. mostra tutti i file il cui nome inizia con zero o più
caratteri (*) seguiti dalla lettera t, poi un
singolo carattere (?), poi ne. seguito da zero
o più caratteri (*). In questo modo si ottiene
octane.pdb e pentane.pdb, ma non corrisponde a
nulla che finisca in thane.pdb.
3. risolve i problemi dell’opzione 2 facendo
corrispondere due caratteri (??) tra t e
ne. Questa è la soluzione.
4. mostra solo i file che iniziano con
ethane..
Altro sui caratteri jolly
Sam ha una cartella contenente i dati di calibrazione, i set di dati e le descrizioni dei set di dati:
BASH
.
├── 2015-10-23-calibration.txt
├── 2015-10-23-dataset1.txt
├── 2015-10-23-dataset2.txt
├── 2015-10-23-dataset_overview.txt
├── 2015-10-26-calibration.txt
├── 2015-10-26-dataset1.txt
├── 2015-10-26-dataset2.txt
├── 2015-10-26-dataset_overview.txt
├── 2015-11-23-calibration.txt
├── 2015-11-23-dataset1.txt
├── 2015-11-23-dataset2.txt
├── 2015-11-23-dataset_overview.txt
├── backup
│ ├── calibration
│ └── datasets
└── send_to_bob
├── all_datasets_created_on_a_23rd
└── all_november_files
Prima di partire per un’altra gita, Sam vuole fare il backup dei suoi dati e inviare alcuni set di dati al suo collega Bob. Per farlo, Sam usa i seguenti comandi:
BASH
$ cp *dataset* backup/datasets
$ cp ____calibration____ backup/calibration
$ cp 2015-____-____ send_to_bob/all_november_files/
$ cp ____ send_to_bob/all_datasets_created_on_a_23rd/
Aiutate Sam a riempire gli spazi vuoti.
La struttura risultante dovrebbe essere la seguente
BASH
.
├── 2015-10-23-calibration.txt
├── 2015-10-23-dataset1.txt
├── 2015-10-23-dataset2.txt
├── 2015-10-23-dataset_overview.txt
├── 2015-10-26-calibration.txt
├── 2015-10-26-dataset1.txt
├── 2015-10-26-dataset2.txt
├── 2015-10-26-dataset_overview.txt
├── 2015-11-23-calibration.txt
├── 2015-11-23-dataset1.txt
├── 2015-11-23-dataset2.txt
├── 2015-11-23-dataset_overview.txt
├── backup
│ ├── calibration
│ │ ├── 2015-10-23-calibration.txt
│ │ ├── 2015-10-26-calibration.txt
│ │ └── 2015-11-23-calibration.txt
│ └── datasets
│ ├── 2015-10-23-dataset1.txt
│ ├── 2015-10-23-dataset2.txt
│ ├── 2015-10-23-dataset_overview.txt
│ ├── 2015-10-26-dataset1.txt
│ ├── 2015-10-26-dataset2.txt
│ ├── 2015-10-26-dataset_overview.txt
│ ├── 2015-11-23-dataset1.txt
│ ├── 2015-11-23-dataset2.txt
│ └── 2015-11-23-dataset_overview.txt
└── send_to_bob
├── all_datasets_created_on_a_23rd
│ ├── 2015-10-23-dataset1.txt
│ ├── 2015-10-23-dataset2.txt
│ ├── 2015-10-23-dataset_overview.txt
│ ├── 2015-11-23-dataset1.txt
│ ├── 2015-11-23-dataset2.txt
│ └── 2015-11-23-dataset_overview.txt
└── all_november_files
├── 2015-11-23-calibration.txt
├── 2015-11-23-dataset1.txt
├── 2015-11-23-dataset2.txt
└── 2015-11-23-dataset_overview.txt
Organizzazione di cartelle e file
Jamie sta lavorando a un progetto e vede che i suoi file non sono ben organizzati:
OUTPUT
analyzed/ fructose.dat raw/ sucrose.dat
I file fructose.dat e sucrose.dat
contengono l’output dell’analisi dei dati. Quale/i comando/i trattato/i
in questa lezione deve eseguire affinché i comandi sottostanti producano
l’output mostrato?
OUTPUT
analyzed/ raw/
OUTPUT
fructose.dat sucrose.dat
Riprodurre la struttura della cartella
si sta iniziando un nuovo esperimento e si vuole duplicare la struttura delle directory dell’esperimento precedente per poter aggiungere nuovi dati.
Si supponga che l’esperimento precedente si trovi in una cartella
chiamata 2016-05-18, che contiene una cartella
data che a sua volta contiene cartelle chiamate
raw e processed che contengono file di dati.
L’obiettivo è copiare la struttura delle cartelle della cartella
2016-05-18 in una cartella chiamata
2016-05-20, in modo che la struttura finale delle cartelle
sia la seguente:
OUTPUT
2016-05-20/
└── data
├── processed
└── raw
Quale dei seguenti comandi raggiungerebbe questo obiettivo? Cosa farebbero gli altri comandi?
Le prime due serie di comandi raggiungono questo obiettivo. La prima serie utilizza percorsi relativi per creare la cartella di primo livello prima delle sottocartelle.
La terza serie di comandi darà un errore perché il comportamento
predefinito di mkdir non crea una sottocartella di una
cartella inesistente: le cartelle di livello intermedio devono essere
create per prime.
La quarta serie di comandi raggiunge questo obiettivo. Ricordate che
l’opzione -p, seguita da un percorso di una o più cartelle,
farà sì che mkdir crei tutte le sottocartelle intermedie
necessarie.
La serie finale di comandi genera le cartelle ‘raw’ e ‘processed’ allo stesso livello della cartella ‘data’.
-
cp [old] [new]copia un file. -
mkdir [path]crea una nuova cartella. -
mv [old] [new]sposta (rinomina) un file o una cartella. -
rm [path]rimuove (elimina) un file. -
*corrisponde a zero o più caratteri in un nome di file, quindi*.txtcorrisponde a tutti i file che terminano in.txt. -
?corrisponde a qualsiasi singolo carattere in un nome di file, quindi?.txtcorrisponde aa.txtma non aany.txt. - L’uso del tasto Control può essere descritto in molti modi, tra cui
Ctrl-X,Control-Xe^X. - La shell non ha un cestino: una volta che qualcosa è stato cancellato, è davvero sparito.
- La maggior parte dei nomi dei file è
something.extension. L’estensione non è necessaria e non garantisce nulla, ma viene normalmente utilizzata per indicare il tipo di dati contenuti nel file. - A seconda del tipo di lavoro svolto, potrebbe essere necessario un editor di testo più potente di Nano.
Content from 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).
Content from Cicli
Ultimo aggiornamento il 2025-11-07 | Modifica questa pagina
Tempo stimato: 50 minuti
Panoramica
Domande
- Come posso eseguire le stesse azioni su molti file diversi?
Obiettivi
- Scrivere un ciclo che applichi uno o più comandi separatamente a ciascun file di un insieme di file.
- Tracciare dei valori assunti da una variabile del ciclo durante la sua esecuzione.
- Spiegare la differenza tra il nome di una variabile e il suo valore.
- Spiegare perché gli spazi e alcuni caratteri di punteggiatura non dovrebbero essere usati nei nomi dei file.
- Dimostrare come vedere quali comandi sono stati eseguiti di recente.
- Eseguire nuovamente i comandi eseguiti di recente senza riscriverli.
I loop sono un costrutto di programmazione che ci permette di ripetere un comando o un insieme di comandi per ogni elemento di un elenco. In quanto tali, sono fondamentali per migliorare la produttività attraverso l’automazione. Analogamente ai caratteri jolly e al completamento delle schede, l’uso dei cicli riduce anche la quantità di battitura necessaria (e quindi il numero di errori di battitura).
Supponiamo di avere diverse centinaia di file di dati del genoma
denominati basilisk.dat, minotaur.dat e
unicorn.dat. Per questo esempio, utilizzeremo la directory
exercise-data/creatures che contiene solo tre file di
esempio, ma i principi possono essere applicati a molti più file
contemporaneamente.
La struttura di questi file è la stessa: il nome comune, la classificazione e la data di aggiornamento sono presentati sulle prime tre righe, con le sequenze di DNA sulle righe successive. Esaminiamo i file:
Vorremmo stampare la classificazione di ogni specie, che è riportata
nella seconda riga di ogni file. Per ogni file, dobbiamo eseguire il
comando head -n 2 e inviarlo a tail -n 1. Per
risolvere questo problema utilizzeremo un ciclo, ma prima vediamo la
forma generale di un ciclo, utilizzando lo pseudo-codice seguente:
BASH
# "for" indica l'inizio di un "For-loop"
for thing in list_of_things
# "do" indica l'inizio dell'esecuzione
do
# L'intentazione non è richiesta ma rende il codice più leggibile
operation_using/command $thing
# "done" indica la fine del for loop
done
e possiamo applicarla al nostro esempio in questo modo:
BASH
$ for filename in basilisk.dat minotaur.dat unicorn.dat
> do
> echo $filename
> head -n 2 $filename | tail -n 1
> done
OUTPUT
basilisk.dat
CLASSIFICATION: basiliscus vulgaris
minotaur.dat
CLASSIFICATION: bos hominus
unicorn.dat
CLASSIFICATION: equus monoceros
Seguire il prompt
Il prompt della shell cambia da $ a > e
viceversa mentre digitiamo il nostro ciclo. Il secondo prompt,
>, è diverso per ricordarci che non abbiamo ancora
finito di digitare un comando completo. Il punto e virgola,
;, può essere usato per separare due comandi scritti su una
singola riga.
Quando la shell vede la parola chiave for, sa che deve
ripetere un comando (o un gruppo di comandi) una volta per ogni elemento
di un elenco. Ogni volta che il ciclo viene eseguito (chiamato
iterazione), un elemento dell’elenco viene assegnato in sequenza alla
variabile e i comandi all’interno del ciclo vengono
eseguiti, prima di passare all’elemento successivo dell’elenco.
All’interno del ciclo, si richiede il valore della variabile anteponendo
$. La $ indica all’interprete della shell di
trattare la variabile come un nome di variabile e di sostituire il suo
valore al suo posto, anziché trattarla come un testo o un comando
esterno.
In questo esempio, l’elenco è costituito da tre nomi di file:
basilisk.dat, minotaur.dat e
unicorn.dat. Ogni volta che il ciclo itera, si usa prima
echo per stampare il valore che la variabile
$filename contiene attualmente. Questo non è necessario ai
fini del risultato, ma è utile per seguire più facilmente la procedura.
Successivamente, verrà eseguito il comando head sul file a
cui fa riferimento $filename. La prima volta che viene
eseguito il ciclo, $filename è basilisk.dat.
L’interprete esegue il comando head su
basilisk.dat e trasmette le prime due righe al comando
tail, che stampa la seconda riga di
basilisk.dat. Per la seconda iterazione,
$filename diventa minotaur.dat. Questa volta,
la shell esegue head su minotaur.dat e invia
le prime due righe al comando tail, che stampa la seconda
riga di minotaur.dat. Per la terza iterazione,
$filename diventa unicorn.dat, quindi la shell
esegue il comando head su quel file e tail sul
suo output. Poiché l’elenco era composto da soli tre elementi, la shell
esce dal ciclo for.
Stessi simboli, significati diversi
Qui vediamo > usato come prompt della shell, mentre
> è usato anche per reindirizzare l’output. Allo stesso
modo, $ è usato come prompt della shell, ma, come abbiamo
visto prima, è anche usato per chiedere alla shell di ottenere il valore
di una variabile.
Se la shell stampa > o $,
allora si aspetta che venga digitato qualcosa, e il simbolo è un
prompt.
Se si digita > o $, si tratta di
un’istruzione che indica alla shell di reindirizzare l’output o di
ottenere il valore di una variabile.
Quando si usano le variabili è anche possibile mettere i nomi tra
parentesi graffe per delimitare chiaramente il nome della variabile:
$filename è equivalente a ${filename}, ma è
diverso da ${file}name. È possibile trovare questa
notazione nei programmi di altre persone.
Abbiamo chiamato la variabile in questo ciclo filename
per rendere il suo scopo più chiaro ai lettori umani. Alla shell stessa
non interessa come viene chiamata la variabile; se scrivessimo questo
ciclo come:
o:
BASH
$ for temperature in basilisk.dat minotaur.dat unicorn.dat
> do
> head -n 2 $temperature | tail -n 1
> done
funzionerebbe esattamente allo stesso modo. *I programmi sono utili
solo se le persone possono capirli, quindi nomi senza senso (come
x) o fuorvianti (come temperature) aumentano
le probabilità che il programma non faccia ciò che i lettori pensano che
faccia.
Negli esempi precedenti, alle variabili (thing,
filename, x e temperature) si
sarebbe potuto dare qualsiasi altro nome, purché significativo sia per
chi scrive il codice sia per chi lo legge.
Si noti anche che i cicli possono essere usati per cose diverse dai nomi di file, come un elenco di numeri o un sottoinsieme di dati.
Scrivete il vostro ciclo personale
Come si scrive un ciclo che fa l’eco di tutti i 10 numeri da 0 a 9?
Variabili nei loop
Questo esercizio si riferisce alla cartella
shell-lesson-data/exercise-data/alkanes. la cartella
ls *.pdb fornisce il seguente output:
OUTPUT
cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
Qual è l’output del seguente codice?
Ora, qual è l’output del seguente codice?
Perché questi due cicli danno risultati diversi?
Il primo blocco di codice dà lo stesso risultato a ogni iterazione
del ciclo. Bash espande il carattere jolly *.pdb
all’interno del corpo del ciclo (e anche prima dell’inizio del ciclo) in
modo che corrisponda a tutti i file che terminano con .pdb
e poi li elenca usando ls. Il ciclo espanso avrebbe il
seguente aspetto:
BASH
$ for datafile in cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
> do
> ls cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
> done
OUTPUT
cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
Il secondo blocco di codice elenca un file diverso a ogni iterazione
del ciclo. Il valore della variabile datafile viene
valutato con $datafile e poi elencato con
ls.
OUTPUT
cubane.pdb
ethane.pdb
methane.pdb
octane.pdb
pentane.pdb
propane.pdb
Limitare gli insiemi di file
Quale sarebbe l’output dell’esecuzione del seguente ciclo nella
directory shell-lesson-data/exercise-data/alkanes?
- Non sono elencati file.
- Tutti i file sono elencati.
- Sono elencati solo
cubane.pdb,octane.pdbepentane.pdb. - Viene elencato solo
cubane.pdb.
4 è la risposta corretta. * corrisponde a zero o più
caratteri, quindi qualsiasi nome di file che inizia con la lettera c,
seguita da zero o più altri caratteri, verrà trovato.
Limitare gli insiemi di file (continued)
In che modo l’output sarebbe diverso se si usasse invece questo comando?
- verrebbero elencati gli stessi file.
- Questa volta vengono elencati tutti i file.
- Questa volta non sono elencati file.
- I file
cubane.pdbeoctane.pdbsaranno elencati. - Verrà elencato solo il file
octane.pdb.
4 è la risposta corretta. * corrisponde a zero o più
caratteri, quindi un nome di file con zero o più caratteri prima di una
lettera c e zero o più caratteri dopo la lettera c sarà corrisposto.
Salvataggio su un file in un ciclo - Prima parte
Nella cartella shell-lesson-data/exercise-data/alkanes,
qual è l’effetto di questo ciclo?
- Stampa
cubane.pdb,ethane.pdb,methane.pdb,octane.pdb,pentane.pdbepropane.pdb, e il testo dipropane.pdbsarà salvato in un file chiamatoalkanes.pdb. - stampa
cubane.pdb,ethane.pdbemethane.pdb, e il testo di tutti e tre i file viene concatenato e salvato in un file chiamatoalkanes.pdb. - Stampa
cubane.pdb,ethane.pdb,methane.pdb,octane.pdbepentane.pdb, e il testo dipropane.pdbsarà salvato in un file chiamatoalkanes.pdb. - Nessuno dei precedenti.
- il testo di ogni file viene scritto a turno nel file
alkanes.pdb. Tuttavia, il file viene sovrascritto a ogni iterazione del ciclo, quindi il contenuto finale dialkanes.pdbè il testo del filepropane.pdb.
Salvataggio su un file in un ciclo - Parte seconda
Sempre nella cartella
shell-lesson-data/exercise-data/alkanes, quale sarebbe
l’output del seguente ciclo?
- Tutto il testo di
cubane.pdb,ethane.pdb,methane.pdb,octane.pdbepentane.pdbverrebbe concatenato e salvato in un file chiamatoall.pdb. - Il testo di
ethane.pdbverrà salvato in un file chiamatoall.pdb. - Tutto il testo di
cubane.pdb,ethane.pdb,methane.pdb,octane.pdb,pentane.pdbepropane.pdbverrebbe concatenato e salvato in un file chiamatoall.pdb. - Tutto il testo di
cubane.pdb,ethane.pdb,methane.pdb,octane.pdb,pentane.pdbepropane.pdbverrebbe stampato sullo schermo e salvato in un file chiamatoall.pdb.
3 è la risposta corretta. >> aggiunge a un file,
invece di sovrascriverlo con l’output rediretto da un comando. Dato che
l’output del comando cat è stato reindirizzato, non viene
stampato nulla sullo schermo.
Continuiamo con il nostro esempio nella cartella
shell-lesson-data/exercise-data/creatures. Ecco un ciclo
leggermente più complicato:
La shell inizia espandendo *.dat per creare l’elenco dei
file che elaborerà. Il corpo del ciclo esegue quindi
due comandi per ciascuno di questi file. Il primo comando,
echo, stampa i suoi argomenti della riga di comando sullo
standard output. Ad esempio:
stampa:
OUTPUT
hello there
In questo caso, poiché la shell espande $filename come
nome di un file, echo $filename stampa il nome del file. Si
noti che non si può scrivere come:
perché così la prima volta nel ciclo, quando $filename
si espande in basilisk.dat, la shell cercherebbe di
eseguire basilisk.dat come programma. Infine, la
combinazione head e tail seleziona le righe da
81 a 100 da qualsiasi file venga elaborato (assumendo che il file abbia
almeno 100 righe).
Spazi nei nomi
Gli spazi sono usati per separare gli elementi dell’elenco su cui si vuole eseguire il ciclo. Se uno di questi elementi contiene un carattere di spazio, dobbiamo circondarlo con le virgolette e fare la stessa cosa con la nostra variabile loop. Supponiamo che i nostri file di dati si chiamino:
red dragon.dat
purple unicorn.dat
Per eseguire il ciclo su questi file, occorre aggiungere i doppi apici in questo modo:
BASH
$ for filename in "red dragon.dat" "purple unicorn.dat"
> do
> head -n 100 "$filename" | tail -n 20
> done
È più semplice evitare di usare spazi (o altri caratteri speciali) nei nomi dei file.
I file di cui sopra non esistono, quindi se si esegue il codice
precedente, il comando head non sarà in grado di trovarli;
tuttavia, il messaggio di errore restituito mostrerà il nome dei file
che si aspetta:
ERRORE
head: cannot open ‘red dragon.dat' for reading: No such file or directory
head: cannot open ‘purple unicorn.dat' for reading: No such file or directory
Provate a rimuovere le virgolette intorno a $filename
nel ciclo precedente per vedere l’effetto delle virgolette sugli spazi.
Si noti che si ottiene un risultato dal comando loop per unicorn.dat
quando si esegue questo codice nella directory
creatures:
OUTPUT
head: cannot open ‘red' for reading: No such file or directory
head: cannot open ‘dragon.dat' for reading: No such file or directory
head: cannot open ‘purple' for reading: No such file or directory
CGGTACCGAA
AAGGGTCGCG
CAAGTGTTCC
...
Vogliamo modificare ciascuno dei file in
shell-lesson-data/exercise-data/creatures, ma anche salvare
una versione dei file originali. Vogliamo copiare i file originali in
nuovi file chiamati original-basilisk.dat e
original-unicorn.dat, per esempio. Non possiamo usare:
perché si espanderebbe in:
Questo non avrebbe eseguito il backup dei nostri file, invece si ottiene un errore:
ERRORE
cp: target `original-*.dat' is not a directory
Questo problema si presenta quando cp riceve più di due
input. Quando ciò accade, si aspetta che l’ultimo ingresso sia una
cartella in cui copiare tutti i file che gli sono stati passati. Poiché
non esiste una cartella denominata original-*.dat nella
cartella creatures, si ottiene un errore.
Invece, possiamo usare un ciclo:
Questo ciclo esegue il comando cp una volta per ogni
nome di file. La prima volta, quando $filename si espande a
basilisk.dat, la shell esegue:
La seconda volta, il comando è:
La terza e ultima volta, il comando è:
Poiché il comando cp normalmente non produce alcun
output, è difficile verificare che il ciclo funzioni correttamente.
Tuttavia, abbiamo imparato in precedenza a stampare stringhe usando
echo e possiamo modificare il ciclo per usare
echo per stampare i nostri comandi senza eseguirli.
Possiamo quindi verificare quali comandi verrebbero eseguiti nel ciclo
non modificato.
Il diagramma seguente mostra cosa succede quando viene eseguito il
ciclo modificato e dimostra come l’uso giudizioso di echo
sia una buona tecnica di debug.
Pipeline di Nelle: Elaborazione dei file
Nelle è ora pronta a elaborare i suoi file di dati usando
goostats.sh — uno script di shell scritto dal suo
supervisore. Questo calcola alcune statistiche da un file campione di
proteine e prende due argomenti:
- un file di ingresso (contenente i dati grezzi)
- un file di uscita (per memorizzare le statistiche calcolate)
Poiché sta ancora imparando a usare la shell, decide di costruire i
comandi necessari per gradi. Il primo passo consiste nell’assicurarsi di
poter selezionare i giusti file di input — ricordate, questi sono quelli
i cui nomi terminano in ‘A’ o ‘B’, piuttosto che in ‘Z’. Spostandosi
nella cartella north-pacific-gyre, Nelle digita:
BASH
$ cd
$ cd Desktop/shell-lesson-data/north-pacific-gyre
$ for datafile in NENE*A.txt NENE*B.txt
> do
> echo $datafile
> done
OUTPUT
NENE01729A.txt
NENE01736A.txt
NENE01751A.txt
...
NENE02040B.txt
NENE02043B.txt
Il passo successivo è decidere come chiamare i file che il programma
di analisi goostats.sh creerà. Prefissare il nome di ogni
file di input con “stats” sembra semplice, quindi modifica il suo ciclo
per farlo:
OUTPUT
NENE01729A.txt stats-NENE01729A.txt
NENE01736A.txt stats-NENE01729A.txt
NENE01751A.txt stats-NENE01729A.txt
...
NENE02040B.txt stats-NENE02040B.txt
NENE02043B.txt stats-NENE02043B.txt
Non ha ancora eseguito goostats.sh, ma ora è sicura di
poter selezionare i file giusti e generare i giusti nomi di file di
output.
Digitare più volte i comandi sta diventando noioso e Nelle è preoccupata di commettere errori, quindi invece di rientrare nel ciclo, preme ↑. In risposta, la shell ripropone l’intero ciclo su una riga (usando i punti e virgola per separare i pezzi):
Utilizzando il comando ←, Nelle passa al comando
echo e lo cambia in bash goostats.sh:
quando si preme Invio, la shell esegue il comando modificato. Tuttavia, non sembra accadere nulla: non c’è output. Dopo un attimo, Nelle si rende conto che, poiché il suo script non stampa più nulla sullo schermo, non ha idea se sia in esecuzione, e tanto meno a quale velocità. Uccide il comando in esecuzione digitando Ctrl+C, usa ↑ per ripetere il comando e lo modifica in modo da leggere:
BASH
$ for datafile in NENE*A.txt NENE*B.txt; do echo $datafile;
bash goostats.sh $datafile stats-$datafile; done
Inizio e fine
Possiamo spostarci all’inizio di una riga nella shell digitando Ctrl+A e alla fine usando Ctrl+E.
Quando il programma viene eseguito ora, produce una riga di output ogni cinque secondi circa:
OUTPUT
NENE01729A.txt
NENE01736A.txt
NENE01751A.txt
...
1518 per 5 secondi, diviso per 60, indica che il suo script
impiegherà circa due ore per essere eseguito. Come controllo finale,
apre un’altra finestra di terminale, entra in
north-pacific-gyre e usa
cat stats-NENE01729B.txt per esaminare uno dei file di
output. Sembra tutto a posto, quindi decide di prendere un caffè e di
mettersi in pari con la lettura.
Chi conosce la storia può scegliere di ripeterla
Un altro modo per ripetere il lavoro precedente è quello di usare il
comando history per ottenere un elenco delle ultime
centinaia di comandi eseguiti, e poi usare !123 (dove ‘123’
è sostituito dal numero del comando) per ripetere uno di quei comandi.
Ad esempio, se Nelle digita questo:
OUTPUT
456 for datafile in NENE*A.txt NENE*B.txt; do echo $datafile stats-$datafile; done
457 for datafile in NENE*A.txt NENE*B.txt; do echo $datafile stats-$datafile; done
458 for datafile in NENE*A.txt NENE*B.txt; do bash goostats.sh $datafile stats-$datafile; done
459 for datafile in NENE*A.txt NENE*B.txt; do echo $datafile; bash goostats.sh $datafile
stats-$datafile; done
460 history | tail -n 5
quindi può eseguire nuovamente goostats.sh sui file
semplicemente digitando !459.
Altri comandi della cronologia
Esistono numerosi altri comandi di scelta rapida per accedere alla cronologia.
- Ctrl+R entra in modalità di ricerca nella cronologia ‘reverse-i-search’ e trova il comando più recente nella cronologia che corrisponde al testo inserito successivamente. Premere Ctrl+R una o più volte per cercare le corrispondenze precedenti. È quindi possibile utilizzare i tasti freccia sinistra e destra per scegliere la riga e modificarla, quindi premere Return per eseguire il comando.
-
!!recupera il comando immediatamente precedente (si può trovare o meno più conveniente che usare ↑) -
!$recupera l’ultima parola dell’ultimo comando. Questo è utile più spesso di quanto ci si possa aspettare: dopobash goostats.sh NENE01729B.txt stats-NENE01729B.txt, si può digitareless !$per guardare il filestats-NENE01729B.txt, il che è più veloce che fare ↑ e modificare la riga di comando.
Esecuzione a secco
Un ciclo è un modo per fare molte cose contemporaneamente — o per
fare molti errori contemporaneamente se fa la cosa sbagliata. Un modo
per verificare cosa farebbe un ciclo è quello di echo i
comandi che eseguirebbe invece di eseguirli effettivamente.
Supponiamo di voler vedere in anteprima i comandi che il seguente ciclo eseguirà senza eseguirli effettivamente:
Qual è la differenza tra i due cicli sottostanti e quale vogliamo eseguire?
La seconda versione è quella che vogliamo eseguire. Questa stampa
sullo schermo tutto ciò che è racchiuso tra le virgolette, espandendo il
nome della variabile del ciclo perché lo abbiamo preceduto da un segno
di dollaro. Inoltre, non modifica e non crea il file
all.pdb, poiché >> viene trattato
letteralmente come parte di una stringa e non come un’istruzione di
reindirizzamento.
La prima versione aggiunge l’output del comando
echo cat $datafile al file all.pdb. Questo
file conterrà solo l’elenco: cat cubane.pdb,
cat ethane.pdb, cat methane.pdb ecc.
provate voi stessi entrambe le versioni per vedere l’output!
Assicurarsi di aprire il file all.pdb per visualizzarne il
contenuto.
Cicli annidati
Supponiamo di voler impostare una struttura di directory per organizzare alcuni esperimenti di misurazione delle costanti di velocità di reazione con diversi composti e diverse temperature. Quale sarebbe il risultato del seguente codice:
Abbiamo un ciclo annidato, cioè contenuto all’interno di un altro ciclo, quindi per ogni specie nel ciclo esterno, il ciclo interno (il ciclo annidato) itera sull’elenco delle temperature e crea una nuova cartella per ogni combinazione.
provate voi stessi a eseguire il codice per vedere quali cartelle vengono create!
- Un ciclo
forripete i comandi una volta per ogni cosa in un elenco. - Ogni ciclo
forha bisogno di una variabile per riferirsi alla cosa su cui sta operando. - Usare
$nameper espandere una variabile (cioè per ottenere il suo valore). si può usare anche${name}. - Non usare spazi, virgolette o caratteri jolly come ‘*’ o ‘?’ nei nomi dei file, perché complicano l’espansione delle variabili.
- Dare ai file nomi coerenti e facili da abbinare con i caratteri jolly, per facilitarne la selezione per il loop.
- Usare il tasto freccia su per scorrere i comandi precedenti e modificarli e ripeterli.
- Usare Ctrl+R per cercare tra i comandi precedentemente inseriti.
- Usare
historyper visualizzare i comandi recenti e![number]per ripetere un comando per numero.
Content from Script di shell
Ultimo aggiornamento il 2025-11-07 | Modifica questa pagina
Tempo stimato: 45 minuti
Panoramica
Domande
- Come posso salvare e riutilizzare i comandi?
Obiettivi
- Scrivere uno script di shell che esegua un comando o una serie di comandi per un insieme fisso di file.
- Eseguire uno script di shell dalla riga di comando.
- Scrive uno script di shell che opera su un insieme di file definiti dall’utente sulla riga di comando.
- Creare pipeline che includano script di shell scritti da voi e da altri.
Siamo finalmente pronti a vedere cosa rende la shell un ambiente di programmazione così potente. Prenderemo i comandi che ripetiamo frequentemente e li salveremo in file, in modo da poter rieseguire tutte le operazioni in un secondo momento digitando un solo comando. Per ragioni storiche, un gruppo di comandi salvati in un file viene solitamente chiamato scritto di shell, ma non fatevi ingannare: si tratta in realtà di piccoli programmi.
La scrittura di script di shell non solo renderà il lavoro più veloce, ma eviterà anche di dover ridigitare gli stessi comandi più volte. Inoltre, il lavoro sarà più accurato (meno possibilità di errori di battitura) e più riproducibile. Se si torna al proprio lavoro in un secondo momento (o se qualcun altro trova il proprio lavoro e vuole basarsi su di esso), sarà possibile riprodurre gli stessi risultati semplicemente eseguendo il proprio script, invece di dover ricordare o digitare nuovamente un lungo elenco di comandi.
Iniziamo tornando a alkanes/ e creando un nuovo file,
middle.sh, che diventerà il nostro script di shell:
Il comando nano middle.sh apre il file
middle.sh all’interno dell’editor di testo ‘nano’ (che
viene eseguito all’interno della shell). Se il file non esiste, verrà
creato. È possibile utilizzare l’editor di testo per modificare
direttamente il file inserendo la seguente riga:
head -n 15 octane.pdb | tail -n 5
Questa è una variante della pipe costruita in precedenza, che
seleziona le righe 11-15 del file octane.pdb. Ricordate che
non lo stiamo ancora eseguendo come comando; stiamo solo incorporando i
comandi in un file.
Poi si salva il file (Ctrl-O in nano) e si esce
dall’editor di testo (Ctrl-X in nano). Verificare che la
cartella alkanes contenga ora un file chiamato
middle.sh.
Una volta salvato il file, possiamo chiedere alla shell di eseguire i
comandi in esso contenuti. La nostra shell si chiama bash,
quindi eseguiamo il seguente comando:
OUTPUT
ATOM 9 H 1 -4.502 0.681 0.785 1.00 0.00
ATOM 10 H 1 -5.254 -0.243 -0.537 1.00 0.00
ATOM 11 H 1 -4.357 1.252 -0.895 1.00 0.00
ATOM 12 H 1 -3.009 -0.741 -1.467 1.00 0.00
ATOM 13 H 1 -3.172 -1.337 0.206 1.00 0.00
Sicuramente l’output del nostro script è esattamente quello che otterremmo se eseguissimo direttamente la pipeline.
Testo vs. Qualsiasi cosa
Di solito chiamiamo “editor di testo” programmi come Microsoft Word o
LibreOffice Writer, ma dobbiamo essere un po’ più attenti quando si
tratta di programmazione. Per impostazione predefinita, Microsoft Word
utilizza i file .docx per memorizzare non solo il testo, ma
anche le informazioni di formattazione relative a caratteri,
intestazioni e così via. Queste informazioni extra non sono memorizzate
come caratteri e non hanno alcun significato per strumenti come
head, che si aspetta che i file di input contengano solo le
lettere, le cifre e la punteggiatura di una tastiera standard. Quando si
modificano i programmi, quindi, è necessario utilizzare un editor di
testo normale o fare attenzione a salvare i file come testo normale.
E se volessimo selezionare delle righe da un file arbitrario?
Potremmo modificare middle.sh ogni volta per cambiare il
nome del file, ma questo probabilmente richiederebbe più tempo che
digitare nuovamente il comando nella shell ed eseguirlo con un nuovo
nome di file. Modifichiamo invece middle.sh e rendiamolo
più versatile:
Ora, all’interno di “nano”, sostituire il testo
octane.pdb con la variabile speciale chiamata
$1:
head -n 15 "$1" | tail -n 5
All’interno di uno script di shell, $1 significa “il
primo nome di file (o altro argomento) sulla riga di comando”. Ora
possiamo eseguire il nostro script in questo modo:
OUTPUT
ATOM 9 H 1 -4.502 0.681 0.785 1.00 0.00
ATOM 10 H 1 -5.254 -0.243 -0.537 1.00 0.00
ATOM 11 H 1 -4.357 1.252 -0.895 1.00 0.00
ATOM 12 H 1 -3.009 -0.741 -1.467 1.00 0.00
ATOM 13 H 1 -3.172 -1.337 0.206 1.00 0.00
o su un file diverso come questo:
OUTPUT
ATOM 9 H 1 1.324 0.350 -1.332 1.00 0.00
ATOM 10 H 1 1.271 1.378 0.122 1.00 0.00
ATOM 11 H 1 -0.074 -0.384 1.288 1.00 0.00
ATOM 12 H 1 -0.048 -1.362 -0.205 1.00 0.00
ATOM 13 H 1 -1.183 0.500 -1.412 1.00 0.00
Doppie virgolette intorno agli argomenti
Per la stessa ragione per cui mettiamo la variabile loop tra
virgolette doppie, nel caso in cui il nome del file contenga spazi,
circondiamo $1 con virgolette doppie.
Attualmente, dobbiamo modificare middle.sh ogni volta
che vogliamo regolare l’intervallo di righe che viene restituito.
Risolviamo questo problema configurando il nostro script in modo che
utilizzi tre argomenti della riga di comando. Dopo il primo argomento da
riga di comando ($1), ogni ulteriore argomento fornito sarà
accessibile tramite le variabili speciali $1,
$2, $3, che si riferiscono rispettivamente al
primo, secondo e terzo argomento da riga di comando.
Sapendo questo, possiamo usare argomenti aggiuntivi per definire
l’intervallo di righe da passare rispettivamente a head e
tail:
head -n "$2" "$1" | tail -n "$3"
Ora possiamo eseguire:
OUTPUT
ATOM 9 H 1 1.324 0.350 -1.332 1.00 0.00
ATOM 10 H 1 1.271 1.378 0.122 1.00 0.00
ATOM 11 H 1 -0.074 -0.384 1.288 1.00 0.00
ATOM 12 H 1 -0.048 -1.362 -0.205 1.00 0.00
ATOM 13 H 1 -1.183 0.500 -1.412 1.00 0.00
Cambiando gli argomenti del nostro comando, possiamo cambiare il comportamento del nostro script:
OUTPUT
ATOM 14 H 1 -1.259 1.420 0.112 1.00 0.00
ATOM 15 H 1 -2.608 -0.407 1.130 1.00 0.00
ATOM 16 H 1 -2.540 -1.303 -0.404 1.00 0.00
ATOM 17 H 1 -3.393 0.254 -0.321 1.00 0.00
TER 18 1
Questo funziona, ma la prossima persona che leggerà
middle.sh potrebbe metterci un attimo a capire cosa fa.
Possiamo migliorare il nostro script aggiungendo alcuni
commenti all’inizio:
# Select lines from the middle of a file.
# Usage: bash middle.sh filename end_line num_lines
head -n "$2" "$1" | tail -n "$3"
Un commento inizia con un carattere # e arriva fino alla
fine della riga. Il computer ignora i commenti, ma sono preziosi per
aiutare le persone (compreso il vostro futuro io) a capire e usare gli
script. L’unica avvertenza è che ogni volta che si modifica lo script,
bisogna controllare che il commento sia ancora corretto. Una spiegazione
che manda il lettore nella direzione sbagliata è peggiore di
nessuna.
Cosa succede se si vogliono elaborare molti file in una singola
pipeline? Per esempio, se vogliamo ordinare i nostri file
.pdb per lunghezza, digitiamo:
perché wc -l elenca il numero di righe nei file
(ricordate che wc sta per “conteggio delle parole”,
aggiungendo l’opzione -l significa invece “conteggio delle
righe”) e sort -n ordina le cose numericamente. Si potrebbe
inserire in un file, ma in questo modo verrebbe ordinato solo un elenco
di file .pdb nella directory corrente. Se vogliamo essere
in grado di ottenere un elenco ordinato di altri tipi di file, abbiamo
bisogno di un modo per inserire tutti questi nomi nello script. Non
possiamo usare $1, $2 e così via perché non
sappiamo quanti file ci sono. Si usa invece la variabile speciale
$@, che significa “Tutti gli argomenti della riga di
comando dello script di shell”. Si dovrebbe anche mettere
$@ tra doppi apici per gestire il caso di argomenti
contenenti spazi ("$@" è una sintassi speciale ed è
equivalente a "$1" "$2" …).
Ecco un esempio:
# Sort files by their length.
# Usage: bash sorted.sh one_or_more_filenames
wc -l "$@" | sort -n
OUTPUT
9 methane.pdb
12 ethane.pdb
15 propane.pdb
20 cubane.pdb
21 pentane.pdb
30 octane.pdb
163 ../creatures/basilisk.dat
163 ../creatures/minotaur.dat
163 ../creatures/unicorn.dat
596 total
Elenco delle specie uniche
Leah ha diverse centinaia di file di dati, ognuno dei quali è formattato in questo modo:
2013-11-05,deer,5
2013-11-05,rabbit,22
2013-11-05,raccoon,7
2013-11-06,rabbit,19
2013-11-06,deer,2
2013-11-06,fox,1
2013-11-07,rabbit,18
2013-11-07,bear,1
Un esempio di questo tipo di file è riportato in
shell-lesson-data/exercise-data/animal-counts/animals.csv.
Possiamo usare il comando
cut -d , -f 2 animals.csv | sort | uniq per produrre le
specie uniche in animals.csv. Per evitare di dover digitare
ogni volta questa serie di comandi, uno scienziato può scegliere di
scrivere uno script di shell.
Scrivere uno script di shell chiamato species.sh che
accetta un numero qualsiasi di nomi di file come argomenti della riga di
comando e utilizza una variante del comando precedente per stampare un
elenco delle specie uniche che compaiono in ciascuno di questi file
separatamente.
BASH
# Script per trovare le specie uniche nei file CSV, dove la specie è il secondo campo di dati.
# Questo script accetta un numero qualsiasi di nomi di file come argomenti da riga di comando.
# Loop over all files
for file in $@
do
echo "Unique species in $file:"
# Estrae i nomi delle specie
cut -d , -f 2 $file | sort | uniq
done
Supponiamo di aver appena eseguito una serie di comandi che hanno fatto qualcosa di utile, ad esempio la creazione di un grafico che vorremmo utilizzare in un articolo. Se vogliamo essere in grado di ricreare il grafico in un secondo momento, vogliamo salvare i comandi in un file. Invece di digitarli di nuovo (e potenzialmente sbagliarli), possiamo fare così:
Il file redo-figure-3.sh ora contiene:
297 bash goostats.sh NENE01729B.txt stats-NENE01729B.txt
298 bash goodiff.sh stats-NENE01729B.txt /data/validated/01729.txt > 01729-differences.txt
299 cut -d ',' -f 2-3 01729-differences.txt > 01729-time-series.txt
300 ygraph --format scatter --color bw --borders none 01729-time-series.txt figure-3.png
301 history | tail -n 5 > redo-figure-3.sh
Dopo un attimo di lavoro in un editor per rimuovere i numeri di serie
sui comandi e per rimuovere la riga finale in cui abbiamo chiamato il
comando history, abbiamo una registrazione completamente
accurata di come abbiamo creato la figura.
Perché registrare i comandi nella cronologia prima di eseguirli?
Se un comando provoca un arresto anomalo o un blocco, potrebbe essere utile sapere qual è il comando in questione, per poter indagare sul problema. Se il comando venisse registrato solo dopo la sua esecuzione, non avremmo una registrazione dell’ultimo comando eseguito in caso di crash.
In pratica, la maggior parte delle persone sviluppa script eseguendo
i comandi al prompt della shell un paio di volte per assicurarsi che
stiano facendo la cosa giusta, poi li salva in un file per
riutilizzarli. Questo stile di lavoro consente di riciclare ciò che si
scopre sui propri dati e sul proprio flusso di lavoro con una sola
chiamata a history e un po’ di modifiche per ripulire
l’output e salvarlo come script di shell.
Pipeline di Nelle: Creazione di uno script
Il supervisore di Nelle ha insistito sul fatto che tutte le sue analisi devono essere riproducibili. Il modo più semplice per catturare tutti i passaggi è uno script.
Per prima cosa torniamo alla directory del progetto di Nelle:
Crea un file usando nano …
… che contiene quanto segue:
BASH
# Calcola le statistiche per i file di dati.
for datafile in "$@"
do
echo $datafile
bash goostats.sh $datafile stats-$datafile
done
Salva il tutto in un file chiamato do-stats.sh, in modo
da poter rifare la prima fase della sua analisi digitando:
Può anche fare questo:
in modo che l’output sia solo il numero di file elaborati piuttosto che i nomi dei file elaborati.
Una cosa da notare dello script di Nelle è che lascia che sia la persona che lo esegue a decidere quali file elaborare. Avrebbe potuto scriverlo come:
BASH
# Calculate stats for Site A and Site B data files.
for datafile in NENE*A.txt NENE*B.txt
do
echo $datafile
bash goostats.sh $datafile stats-$datafile
done
Il vantaggio è che in questo modo si selezionano sempre i file
giusti, senza doversi ricordare di escludere i file “Z”. Lo svantaggio è
che seleziona sempre solo quei file — non può eseguirlo su
tutti i file (compresi i file ‘Z’), o sui file ‘G’ o ‘H’ che i suoi
colleghi in Antartide stanno producendo, senza modificare lo script. Se
volesse essere più avventurosa, potrebbe modificare il suo script per
verificare la presenza di argomenti da riga di comando e usare
NENE*A.txt NENE*B.txt se non ne vengono forniti.
Naturalmente, questo introduce un altro compromesso tra flessibilità e
complessità.
Variabili negli script di shell
Nella cartella alkanes, immaginate di avere uno script
di shell chiamato script.sh contenente i seguenti
comandi:
Mentre ci si trova nella cartella alkanes, si digita il
seguente comando:
Quale dei seguenti risultati vi aspettereste di vedere?
- Tutte le righe tra la prima e l’ultima di ogni file che termina con
.pdbnella cartellaalkanes - La prima e l’ultima riga di ogni file che termina con
.pdbnella cartellaalkanes - La prima e l’ultima riga di ogni file nella cartella
alkanes - Errore a causa delle virgolette intorno a
*.pdb
la risposta corretta è 2.
Le variabili speciali $1, $2 e
$3 rappresentano gli argomenti della riga di comando dati
allo script, in modo che i comandi eseguiti siano:
BASH
$ head -n 1 cubane.pdb ethane.pdb octane.pdb pentane.pdb propane.pdb
$ tail -n 1 cubane.pdb ethane.pdb octane.pdb pentane.pdb propane.pdb
La shell non espande '*.pdb' perché è racchiuso tra
virgolette. Pertanto, il primo argomento dello script è
'*.pdb' che viene espanso all’interno dello script da
head e tail.
Trova il file più lungo con una data estensione
Scrivere uno script di shell chiamato longest.sh che
prenda come argomenti il nome di una cartella e l’estensione di un nome
di file e stampi il nome del file con il maggior numero di righe in
quella cartella con quell’estensione. Ad esempio:
stamperebbe il nome del file .pdb in
shell-lesson-data/exercise-data/alkanes che ha il maggior
numero di righe.
Sentitevi liberi di testare il vostro script su un’altra directory, ad es.
BASH
# Shell script which takes two arguments:
# 1. a directory name
# 2. a file extension
# and prints the name of the file in that directory
# with the most lines which matches the file extension.
wc -l $1/*.$2 | sort -n | tail -n 2 | head -n 1
La prima parte della pipeline, wc -l $1/*.$2 | sort -n,
conta le righe di ogni file e le ordina numericamente (la più grande per
ultima). Quando c’è più di un file, wc produce anche una
riga finale di riepilogo, che dà il numero totale di righe in
tutti i file. Si usa tail -n 2 | head -n 1 per
eliminare quest’ultima riga.
Con wc -l $1/*.$2 | sort -n | tail -n 1 vedremo la riga
di riepilogo finale: possiamo costruire la nostra pipeline a pezzi per
essere sicuri di capire l’output.
Comprensione della lettura degli script
Per questa domanda, consideriamo ancora una volta la cartella
shell-lesson-data/exercise-data/alkanes. Questa contiene
una serie di file .pdb oltre ad altri file eventualmente
creati. Spiegare che cosa farebbe ciascuno dei tre script seguenti se
eseguito rispettivamente come bash script1.sh *.pdb,
bash script2.sh *.pdb e
bash script3.sh *.pdb.
In ogni caso, la shell espande il carattere jolly in
*.pdb prima di passare l’elenco risultante di nomi di file
come argomenti allo script.
Lo script 1 stampa un elenco di tutti i file che contengono un punto nel loro nome. Gli argomenti passati allo script non vengono utilizzati in nessun punto dello script.
Lo script 2 stampa il contenuto dei primi 3 file con estensione
.pdb. $1, $2 e $3 si
riferiscono rispettivamente al primo, al secondo e al terzo
argomento.
Lo script 3 stamperebbe tutti gli argomenti dello script (cioè tutti
i file .pdb), seguiti da .pdb. $@
si riferisce a tutti gli argomenti dati a uno script di
shell.
OUTPUT
cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb.pdb
Script di Debug
Si supponga di aver salvato il seguente script in un file chiamato
do-errors.sh nella cartella north-pacific-gyre
di Nelle:
BASH
# Calculate stats for data files.
for datafile in "$@"
do
echo $datfile
bash goostats.sh $datafile stats-$datafile
done
Quando lo si esegue dalla cartella
north-pacific-gyre:
l’output è vuoto. Per capirne il motivo, rieseguire lo script
utilizzando l’opzione -x:
Cosa mostra l’output? Quale riga è responsabile dell’errore?
L’opzione -x fa sì che bash venga eseguito
in modalità di debug. In questo modo viene stampato ogni comando man
mano che viene eseguito, il che aiuta a individuare gli errori. In
questo esempio, possiamo vedere che echo non sta stampando
nulla. Abbiamo commesso un errore di battitura nel nome della variabile
del ciclo e la variabile datfile non esiste, quindi
restituisce una stringa vuota.
- Salva i comandi in file (di solito chiamati script di shell) per riutilizzarli.
-
bash [filename]esegue i comandi salvati in un file. -
$@si riferisce a tutti gli argomenti della riga di comando di uno script di shell. -
$1,$2, ecc. si riferiscono al primo argomento della riga di comando, al secondo argomento della riga di comando, ecc. - Mettere le variabili tra virgolette se i valori possono contenere spazi.
- Lasciare che siano gli utenti a decidere quali file elaborare è più flessibile e più coerente con i comandi Unix integrati.
Content from Trovare le cose
Ultimo aggiornamento il 2025-11-07 | Modifica questa pagina
Tempo stimato: 45 minuti
Panoramica
Domande
- Come posso trovare i file?
- Come posso trovare le cose nei file?
Obiettivi
- Usare
grepper selezionare righe da file di testo che corrispondono a modelli semplici. - Usare
findper trovare file e cartelle i cui nomi corrispondono a schemi semplici. - Utilizzare l’output di un comando come argomento della riga di comando di un altro comando.
- Spiegare cosa si intende per file “di testo” e “binari” e perché molti strumenti comuni non gestiscono bene questi ultimi.
Allo stesso modo in cui molti di noi usano ‘Google’ come verbo che significa ‘trovare’, i programmatori Unix usano spesso la parola ‘grep’. ‘grep’ è una contrazione di ‘global/regular expression/print’, una sequenza comune di operazioni nei primi editor di testo Unix. È anche il nome di un programma a riga di comando molto utile.
grep trova e stampa le righe dei file che corrispondono
a uno schema. Per i nostri esempi, useremo un file che contiene tre
haiku tratti da un concorso
1998 della rivista Salon (merito degli autori Bill Torcaso,
Howard Korder e Margaret Segall, rispettivamente. Si vedano i messaggi
di errore Haiku archiviati Pagina
1 e Pagina
2). Per questa serie di esempi, lavoreremo nella sottocartella della
scrittura:
OUTPUT
The Tao that is seen
Is not the true Tao, until
You bring fresh toner.
With searching comes loss
and the presence of absence:
"My Thesis" not found.
Yesterday it worked
Today it is not working
Software is like that.
Troviamo le righe che contengono la parola “non”:
OUTPUT
Is not the true Tao, until
"My Thesis" not found
Today it is not working
Qui, not è lo schema che stiamo cercando. Il comando
grep cerca nel file le corrispondenze con lo schema specificato. Per
utilizzarlo, digitare grep, quindi lo schema che si vuole
cercare e infine il nome del file (o dei file) in cui si vuole
effettuare la ricerca.
L’output è costituito dalle tre righe del file che contengono le lettere “non”.
Per impostazione predefinita, grep cerca un modello in modo sensibile alle maiuscole e alle minuscole. Inoltre, il modello di ricerca selezionato non deve necessariamente formare una parola completa, come vedremo nel prossimo esempio.
Cerchiamo il modello: ‘Il’.
OUTPUT
The Tao that is seen
"My Thesis" not found.
Questa volta vengono prodotte due righe che includono le lettere “The”, una delle quali conteneva il nostro modello di ricerca all’interno di una parola più grande, “Thesis”.
Per limitare le corrispondenze alle righe contenenti la parola ‘The’
da sola, si può dare a grep l’opzione -w.
Questo limiterà le corrispondenze ai confini della parola.
Più avanti in questa lezione vedremo anche come modificare il comportamento di ricerca di grep rispetto alla sensibilità alle maiuscole.
OUTPUT
The Tao that is seen
Si noti che un “confine di parola” include l’inizio e la fine di una
riga, quindi non solo le lettere circondate da spazi. A volte non si
vuole cercare una singola parola, ma una frase. È possibile farlo anche
con grep, mettendo la frase tra virgolette.
OUTPUT
Today it is not working
Abbiamo visto che non è necessario mettere le virgolette intorno alle singole parole, ma è utile usare le virgolette quando si cercano più parole. Inoltre, aiuta a distinguere più facilmente tra il termine o la frase di ricerca e il file ricercato. Negli altri esempi utilizzeremo le virgolette.
Un’altra opzione utile è -n, che numera le righe
corrispondenti:
OUTPUT
5:With searching comes loss
9:Yesterday it worked
10:Today it is not working
Qui possiamo vedere che le righe 5, 9 e 10 contengono le lettere “it”.
Possiamo combinare le opzioni (cioè i flag) come facciamo con altri
comandi Unix. Per esempio, cerchiamo di trovare le righe che contengono
la parola “il”. Possiamo combinare l’opzione -w per trovare
le righe che contengono la parola ‘the’ e -n per numerare
le righe che corrispondono:
OUTPUT
2:Is not the true Tao, until
6:and the presence of absence:
Ora vogliamo usare l’opzione -i per rendere la nostra
ricerca insensibile alle maiuscole e alle minuscole:
OUTPUT
1:The Tao that is seen
2:Is not the true Tao, until
6:and the presence of absence:
Ora vogliamo usare l’opzione -v per invertire la nostra
ricerca, cioè vogliamo produrre le righe che non contengono la parola
‘the’.
OUTPUT
1:The Tao that is seen
3:You bring fresh toner.
4:
5:With searching comes loss
7:"My Thesis" not found.
8:
9:Yesterday it worked
10:Today it is not working
11:Software is like that.
Se si usa l’opzione -r (ricorsiva), grep
può cercare un modello in modo ricorsivo in un insieme di file in
sottodirectory.
Cerchiamo ricorsivamente Yesterday nella directory
shell-lesson-data/exercise-data/writing:
OUTPUT
./LittleWomen.txt:"Yesterday, when Aunt was asleep and I was trying to be as still as a
./LittleWomen.txt:Yesterday at dinner, when an Austrian officer stared at us and then
./LittleWomen.txt:Yesterday was a quiet day spent in teaching, sewing, and writing in my
./haiku.txt:Yesterday it worked
grep ha molte altre opzioni. Per scoprire quali sono, si
può digitare:
OUTPUT
Usage: grep [OPTION]... PATTERN [FILE]...
Search for PATTERN in each FILE or standard input.
PATTERN is, by default, a basic regular expression (BRE).
Example: grep -i 'hello world' menu.h main.c
Regexp selection and interpretation:
-E, --extended-regexp PATTERN is an extended regular expression (ERE)
-F, --fixed-strings PATTERN is a set of newline-separated fixed strings
-G, --basic-regexp PATTERN is a basic regular expression (BRE)
-P, --perl-regexp PATTERN is a Perl regular expression
-e, --regexp=PATTERN use PATTERN for matching
-f, --file=FILE obtain PATTERN from FILE
-i, --ignore-case ignore case distinctions
-w, --word-regexp force PATTERN to match only whole words
-x, --line-regexp force PATTERN to match only whole lines
-z, --null-data a data line ends in 0 byte, not newline
Miscellaneous:
... ... ...
Uso di grep
Quale comando produrrebbe il seguente output:
OUTPUT
and the presence of absence:
grep "of" haiku.txtgrep -E "of" haiku.txtgrep -w "of" haiku.txtgrep -i "of" haiku.txt
La risposta corretta è 3, perché l’opzione -w cerca solo
le corrispondenze con le parole intere. Le altre opzioni corrispondono
anche a “di” quando è parte di un’altra parola.
Caratteri jolly
la vera potenza di grep non deriva dalle sue opzioni, ma
dal fatto che i pattern possono includere caratteri jolly. (Il nome
tecnico di queste espressioni è espressioni regolari,
che è il significato di “re” in “grep”) Le espressioni regolari sono
complesse e potenti; se volete fare ricerche complesse, consultate la
lezione su il
nostro sito web. Come assaggio, possiamo trovare le righe che hanno
una ‘o’ in seconda posizione come questa:
OUTPUT
You bring fresh toner.
Today it is not working
Software is like that.
Usiamo l’opzione -E e mettiamo il pattern tra virgolette
per evitare che la shell cerchi di interpretarlo. (Se il pattern
contenesse un *, per esempio, la shell cercherebbe di
espanderlo prima di eseguire grep) Il ^ nel
pattern fissa la corrispondenza all’inizio della riga. La .
corrisponde a un singolo carattere (proprio come la ? nella
shell), mentre la o corrisponde a una “o” vera e
propria.
Tracciare una specie
Leah ha diverse centinaia di file di dati salvati in una directory, ognuno dei quali è formattato come segue:
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
Vuole scrivere uno script di shell che prenda una specie come primo
argomento della riga di comando e una directory come secondo argomento.
Lo script dovrebbe restituire un file chiamato
<species>.txt contenente un elenco di date e il
numero di specie osservate in ciascuna data. Ad esempio, utilizzando i
dati mostrati sopra, rabbit.txt conterrebbe:
2012-11-05,22
2012-11-06,19
2012-11-07,16
Di seguito, ogni riga contiene un singolo comando, o pipe. Organizzare la loro sequenza in un comando per raggiungere l’obiettivo di Leah:
Suggerimento: usare man grep per cercare come grepare il
testo in modo ricorsivo in una cartella e man cut per
selezionare più di un campo in una riga.
Un esempio di tale file è fornito in
shell-lesson-data/exercise-data/animal-counts/animals.csv
grep -w $1 -r $2 | cut -d : -f 2 | cut -d , -f 1,3 > $1.txt
In realtà, è possibile scambiare l’ordine dei due comandi di taglio e funziona ancora. Alla riga di comando, provate a cambiare l’ordine dei comandi di taglio e date un’occhiata all’output di ogni passaggio per capire perché è così.
Lo script precedente viene chiamato in questo modo:
Piccole donne
Tu e la tua amica, dopo aver appena finito di leggere Piccole
donne di Louisa May Alcott, state discutendo. Delle quattro sorelle
del libro, Jo, Meg, Beth e Amy, la vostra amica pensa che Jo sia la più
citata. Voi, invece, siete certi che si tratti di Amy. Fortunatamente si
dispone di un file LittleWomen.txt contenente il testo
completo del romanzo
(shell-lesson-data/exercise-data/writing/LittleWomen.txt).
Utilizzando un ciclo for, come si potrebbe tabulare il
numero di volte in cui ciascuna delle quattro sorelle viene
menzionata?
Suggerimento: una soluzione potrebbe utilizzare i comandi
grep e wc e un |, mentre un’altra
potrebbe utilizzare le opzioni grep. Spesso esiste più di
un modo per risolvere un compito di programmazione, quindi una
particolare soluzione viene solitamente scelta in base a una
combinazione di risultati corretti, eleganza, leggibilità e
velocità.
for sis in Jo Meg Beth Amy
do
echo $sis:
grep -ow $sis LittleWomen.txt | wc -l
done
Soluzione alternativa, leggermente inferiore:
for sis in Jo Meg Beth Amy
do
echo $sis:
grep -ocw $sis LittleWomen.txt
done
Questa soluzione è inferiore perché grep -c riporta solo
il numero di righe corrispondenti. Il numero totale di corrispondenze
riportato da questo metodo sarà inferiore se c’è più di una
corrispondenza per riga.
Gli osservatori più attenti avranno notato che i nomi dei personaggi
a volte appaiono in tutte le maiuscole nei titoli dei capitoli (per
esempio, “MEG VA ALLA FIERA DELLA VANITÀ”). Se si volesse contare anche
questi, si potrebbe aggiungere l’opzione -i per
l’insensibilità alle maiuscole e minuscole (anche se in questo caso non
influisce sulla risposta a quale sorella è menzionata più
frequentemente).
Mentre grep trova le righe nei file, il comando
find trova i file stessi. Anche in questo caso, ha molte
opzioni; per mostrare come funzionano le più semplici, useremo l’albero
shell-lesson-data/exercise-data mostrato di seguito.
OUTPUT
.
├── animal-counts/
│ └── animals.csv
├── creatures/
│ ├── basilisk.dat
│ ├── minotaur.dat
│ └── unicorn.dat
├── numbers.txt
├── alkanes/
│ ├── cubane.pdb
│ ├── ethane.pdb
│ ├── methane.pdb
│ ├── octane.pdb
│ ├── pentane.pdb
│ └── propane.pdb
└── writing/
├── haiku.txt
└── LittleWomen.txt
La cartella exercise-data contiene un file,
numbers.txt e quattro cartelle: animal-counts,
creatures, alkanes e writing
contenenti vari file.
Per il nostro primo comando, eseguiamo find . (ricordate
di eseguire questo comando dalla cartella
shell-lesson-data/exercise-data).
OUTPUT
.
./writing
./writing/LittleWomen.txt
./writing/haiku.txt
./creatures
./creatures/basilisk.dat
./creatures/unicorn.dat
./creatures/minotaur.dat
./animal-counts
./animal-counts/animals.csv
./numbers.txt
./alkanes
./alkanes/ethane.pdb
./alkanes/propane.pdb
./alkanes/octane.pdb
./alkanes/pentane.pdb
./alkanes/methane.pdb
./alkanes/cubane.pdb
Come sempre, . da solo significa la cartella di lavoro
corrente, che è il punto da cui vogliamo iniziare la nostra ricerca.
l’output di find è il nome di ogni file e
cartella sotto la cartella di lavoro corrente. All’inizio può sembrare
inutile, ma find ha molte opzioni per filtrare l’output e
in questa lezione ne scopriremo alcune.
La prima opzione del nostro elenco è -type d che
significa “cose che sono directory”. Certamente, l’output di
find è il nome delle cinque cartelle (inclusa
.):
OUTPUT
.
./writing
./creatures
./animal-counts
./alkanes
Si noti che gli oggetti trovati da find non sono
elencati in un ordine particolare. Se si cambia -type d con
-type f, si ottiene invece un elenco di tutti i file:
OUTPUT
./writing/LittleWomen.txt
./writing/haiku.txt
./creatures/basilisk.dat
./creatures/unicorn.dat
./creatures/minotaur.dat
./animal-counts/animals.csv
./numbers.txt
./alkanes/ethane.pdb
./alkanes/propane.pdb
./alkanes/octane.pdb
./alkanes/pentane.pdb
./alkanes/methane.pdb
./alkanes/cubane.pdb
Ora proviamo a fare una corrispondenza per nome:
OUTPUT
./numbers.txt
Ci si aspettava che trovasse tutti i file di testo, ma stampa solo
./numbers.txt. Il problema è che la shell espande i
caratteri jolly come * prima dell’esecuzione dei
comandi. Poiché *.txt nella cartella corrente si espande a
./numbers.txt, il comando effettivamente eseguito è
stato:
find ha fatto quello che abbiamo chiesto; abbiamo solo
chiesto la cosa sbagliata.
Per ottenere ciò che vogliamo, facciamo come con grep:
mettiamo *.txt tra virgolette per evitare che la shell
espanda il carattere jolly *. In questo modo,
find ottiene effettivamente il pattern *.txt,
non il nome del file espanso numbers.txt:
OUTPUT
./writing/LittleWomen.txt
./writing/haiku.txt
./numbers.txt
Elenco vs. ricerca
ls e find possono fare cose simili con le
giuste opzioni, ma in circostanze normali, ls elenca tutto
ciò che può, mentre find cerca cose con certe proprietà e
le mostra.
Come abbiamo detto prima, la potenza della riga di comando sta nel
combinare gli strumenti. Abbiamo visto come farlo con le pipe; vediamo
un’altra tecnica. Come abbiamo appena visto,
find . -name "*.txt" ci fornisce un elenco di tutti i file
di testo presenti nella cartella corrente o al di sotto di essa. Come
possiamo combinarlo con wc -l per contare le righe in tutti
questi file?
Il modo più semplice è quello di inserire il comando
find all’interno di $():
OUTPUT
21022 ./writing/LittleWomen.txt
11 ./writing/haiku.txt
5 ./numbers.txt
21038 total
Quando la shell esegue questo comando, la prima cosa che fa è
eseguire qualsiasi cosa si trovi all’interno della $().
Quindi sostituisce l’espressione $() con l’output di quel
comando. Poiché l’output di find è costituito dai tre nomi
di file ./writing/LittleWomen.txt,
./writing/haiku.txt e ./numbers.txt, la shell
costruisce il comando:
che è quello che volevamo. Questa espansione è esattamente ciò che fa
la shell quando espande i caratteri jolly come * e
?, ma ci permette di usare qualsiasi comando come nostro
‘carattere jolly’.
È molto comune usare find e grep insieme.
Il primo trova i file che corrispondono a uno schema; il secondo cerca
le righe all’interno di quei file che corrispondono a un altro schema.
Qui, per esempio, possiamo trovare i file txt che contengono la parola
“searching” cercando la stringa ‘searching’ in tutti i file
.txt nella directory corrente:
OUTPUT
./writing/LittleWomen.txt:sitting on the top step, affected to be searching for her book, but was
./writing/haiku.txt:With searching comes loss
Corrispondenza e sottrazione
L’opzione -v di grep inverte la
corrispondenza dei pattern, in modo che vengano stampate solo le righe
che non corrispondono al pattern. In base a ciò, quale dei
seguenti comandi troverà tutti i file .dat in creatures
tranne che in unicorn.dat? Dopo aver pensato alla risposta,
si possono testare i comandi nella directory
shell-lesson-data/exercise-data.
find creatures -name "*.dat" | grep -v unicornfind creatures -name *.dat | grep -v unicorngrep -v "unicorn" $(find creatures -name "*.dat")- Nessuno dei precedenti.
L’opzione 1 è corretta. Mettere l’espressione di corrispondenza tra
virgolette impedisce alla shell di espanderla, quindi viene passata al
comando find.
L’opzione 2 funziona anche in questo caso, perché la shell tenta di
espandere *.dat ma non ci sono file *.dat
nella cartella corrente, quindi l’espressione jolly viene passata a
find. L’abbiamo incontrato per la prima volta in [episodio
3] (03-create.md).
L’opzione 3 non è corretta perché cerca nel contenuto dei file le righe che non corrispondono a “unicorno”, anziché cercare nei nomi dei file.
File binari
Ci siamo concentrati esclusivamente sulla ricerca di modelli nei file di testo. Cosa succede se i dati sono archiviati come immagini, in database o in altri formati?
Una manciata di strumenti estende grep per gestire
alcuni formati diversi dal testo. Ma un approccio più generalizzabile è
quello di convertire i dati in testo o di estrarre gli elementi simili
al testo dai dati. Da un lato, questo rende le cose semplici facili da
fare. D’altra parte, le cose complesse sono di solito impossibili. Per
esempio, è abbastanza facile scrivere un programma che estragga le
dimensioni X e Y da file di immagini per giocare con grep,
ma come si potrebbe scrivere qualcosa per trovare valori in un foglio di
calcolo le cui celle contengono formule?
Un’ultima opzione è riconoscere che la shell e l’elaborazione del testo hanno i loro limiti e utilizzare un altro linguaggio di programmazione. Quando arriva il momento di farlo, non siate troppo duri con la shell. Molti linguaggi di programmazione moderni hanno preso in prestito molte idee da essa, e l’imitazione è anche la forma più sincera di lode.
La shell Unix è più vecchia della maggior parte delle persone che la usano. È sopravvissuta così a lungo perché è uno degli ambienti di programmazione più produttivi mai creati, forse addirittura il più produttivo. La sua sintassi può essere criptica, ma chi la padroneggia può sperimentare diversi comandi in modo interattivo e poi usare ciò che ha imparato per automatizzare il proprio lavoro. Le interfacce utente grafiche possono essere più facili da usare all’inizio, ma una volta imparate, la produttività della shell è imbattibile. E come scrisse Alfred North Whitehead nel 1911, “la civiltà progredisce ampliando il numero di operazioni importanti che possiamo eseguire senza pensarci”
- Trova tutti i file con estensione
.datricorsivamente dalla cartella corrente - Conta il numero di righe contenute in ciascuno di questi file
- Ordina numericamente l’output del passo 2
-
findtrova file con proprietà specifiche che corrispondono ai modelli. -
grepseleziona le righe dei file che corrispondono ai modelli. -
--helpè un’opzione supportata da molti comandi bash e programmi che possono essere eseguiti da Bash, per visualizzare ulteriori informazioni sull’uso di tali comandi o programmi. -
man [command]visualizza la pagina del manuale per un determinato comando. -
$([command])inserisce l’output di un comando al suo posto.