Questo articolo si propone di avvicinare i lettori all’uso della Shell. Avrà un taglio pratico e si rivolgerà prevalentemente a neofiti che però abbiano già un background di programmazione.

Non sarà possibile coprire tutti gli aspetti dell’argomento (in vero non sarà possibile coprire nemmeno un piccola parte di essi) perciò verranno trattati solo alcuni comandi Bash tra quelli più diffusi e utili per gli sviluppatori.

Cos’è una shell

In linea generale, una shell è uno strumento testuale che permette ad un utente di interagire con un computer. Questo avviene tramite l’immissione di comandi in un terminale.

La shell è pensata per nascondere la complessità del sistema operativo sottostante.

In un passato (non troppo) remoto, essa era l’unico strumento disponibile per dialogare con un calcolatore elettronico. Negli ultimi 20/30 anni la sua importanza è stata di molto ridimensionata a causa della diffusione delle interfacce grafiche. Ma questo strumento non è mai diventato obsoleto. Soprattutto in ambito sistemistico e di sviluppo software le sue doti di velocità e versatilità sono ancora molto apprezzate.

Muoversi nel file-system

Tra le prime cose da imparare c’è l’interazione con il file system. Quando aprite un terminale, venite posizionati in una certa cartella. Solitamente si tratta della cartella home dell’utente con cui siete loggati. Potete in ogni momento individuare il path della cartella in cui li trovate con il comando pwd

1
2
$ pwd
/home/david

In ambiente linux, per i path si usa come carattere separatore lo slash ('/'). La cartella radice è indicata con ‘/’. Tutte le altre sono “““figlie” di questa. L’esempio precedente rappresenta un albero fatto in questo modo:

1
2
3
/
+-- home
      +-- david

Per scoprire cosa contiene una cartella, potete usare il comando ls seguito (eventualmente) dal path di cui si vuole visualizzare il contenuto

1
2
$ ls /mnt
c/    d/ 

nell’esempio abbiamo ottenuto il contenuto della cartella /mnt che contiene i filesystem montati sulla nostra macchina. Come accade per la maggior parte dei comandi unix, il funzionamento di base di ls può essere modificato usando opportuni switch. Per ls i più usati sono -l e -a:

1
2
3
$ ls -l /mnt/c/
$ ls -l -a /mnt/c/
$ ls -la /mnt/c/

La prima riga stampa informazioni dettagliate sul contenuto della cartella /mnt/c/. La seconda e la terza fanno lo stesso ma includono anche i file nascosti. Notate che scrivere “-l -a” e “-la” è perfettamente equivalente (ma questo non vale in generale per tutti i comandi). Il comando ls -la ci mostra anche due oggetti speciali: “.” e “..”. Il singolo punto indica la directory attuale mentre i due punti affiancati si riferiscono alla cartella padre. Vedremo più avanti come usarli. Vale la pena spendere qualche parola in più sull’output di ls -l.

1
2
3
$ ls -l temp
drwxr-xr-x  3 david  admin    102 15 Giu 00:34 docs
-rw-r--r--  1 david  admin  18562 15 Giu 00:35 leggimi.txt

abbiamo chiesto l’elenco dettagliato dei file contenuti nella cartella di nome temp. L’output ottenuto riporta numerose informazioni. Per ciascuna riga: il primo carattere indica se l’oggetto è una cartella (’d') o un file ('-'). Seguono poi i permessi, di cui parliamo più diffusamente in un box l’utente owner (david) il gruppo (admin) le dimensioni in byte la data e l’ora di creazione il nome del file o della cartella

I permessi

Nell’articolo, parlando dell’output del comando ls -l, ci siamo imbattuti in una strana stringa fatta più o meno in questo modo:

drwxr-xr-x

Essa ci da informazioni sui permessi associati all’oggetto. Per comprenderne il significato può essere d’aiuto suddividerla in questo modo:

d rwx r-x r-x

Il primo carattere indica se l’oggetto è una directory (‘d’) o un link (‘l’) o un file (‘-’).

Poi ci sono tre gruppi di tre lettere. Questi rappresentano i permessi associati all’oggetto: r w x stanno rispettivamente per read, write, execute. Il primo gruppo di lettere rappresenta i permessi del proprietario (owner) del file; il secondo indica quelli dei membri del gruppo; il terzo infine quello di tutti gli altri. Nell’esempio il proprietario può fare tutto, i membri del gruppo e tutti gli altri utenti possono solo leggere e accedere ma non scrivere (dato che manca la w).

Per spostarsi in una nuova cartella si può usare il comando cd seguito dal path di destinazione.

1
$ cd /mnt/c/windows/

Per “risalire” alla cartella padre di quella corrente possiamo usare il comando cd seguito da due punti “..”

1
2
3
4
5
$ pwd
/mnt/c/windows
$ cd ..
$ pwd
/mnt/c

Manipolare oggetti del File System

Ora che sappiamo come spostarci tra le directory e come elencarne il contenuto, possiamo imparare a creare nuovi oggetti. Per generare una nuova directory possiamo utilizzare il comando mkdir seguito dal nome della nuova cartella

1
$ mkdir temp

Dato che il path che abbiamo specificato non inizia con il carattere ‘/’, sarà considerato relativo alla posizione corrente. Dopo l’esecuzione si ottiene una nuova cartella il cui path (stavolta assoluto dato che inizia con ‘/') è: /mnt/c/temp. E’ possibile eliminare una folder, usando il comando: rmdir

1
$ rmdir temp

Questo comando funziona solo se la cartella da rimuovere è vuota. Vedremo più avanti come fare per cancellare anche quelle che contengono altri oggetti. Non esiste invece un modo unico di creare un file. In genere si usano dei software specifici (editor testuali, applicazioni di grafica, ecc). E' tuttavia abbastanza semplice creare un file vuoto (che “riempiremo” in un secondo momento) usando il comando touch.

1
touch newfile

Touch in realtà serve per “aggiornare” la data di modifica di un file. Se però questo non esiste, viene creato. Dalla teoria alla pratica Abbiamo dichiarato nell’introduzione, di voler dare all’articolo un taglio molto pratico. Cimentiamoci dunque, utilizzando le nozioni imparate fin qui, in un compito un po' più arduo: l’installazione dell’application-server Tomcat usando esclusivamente la riga di comando. Per prima cosa dobbiamo scaricare il pacchetto dal web. A questo scopo possiamo servirci di wget. Wget e definito come un “downloader non interattivo”. Semplificando, ci permette di scaricare file da un indirizzo web.

1
2
3
4
5
6
$ mkdir server
$ cd server
$ wget http://it.apache.contactlab.it/tomcat/tomcat-8/v8.0.36/bin/apache-tomcat-8.0.36.tar.gz
[...]
$ ls
apache-tomcat-8.0.36.tar.gz

Nelle prime due righe abbiamo creato una cartella di nome server e ci siamo spostati al suo interno. Abbiamo usato poi wget per scaricare il pacchetto contenente Tomcat 8. Dopo qualche secondo il file sarà presente nella cartella server. Possiamo verificarlo con il comando ls. Il pacchetto è compresso in un formato molto comune nel mondo linux: tar.gz Per decomprimerlo possiamo usare tar:

1
2
3
4
5
$ tar -xvf apache-tomcat-8.0.36.tar.gz
[...]
$ ls -l
drwxr-xr-x  13 david  admin      442 16 Giu 00:03 apache-tomcat-8.0.36
-rw-r--r--   1 david  admin  9277365  9 Giu 16:16 apache-tomcat-8.0.36.tar.gz

Per effetto del comando tar abbiamo una nuova cartella di nome apache-tomcat-8.0.36. Spostiamoci in essa ed elenchiamo i file che contiene

1
2
3
4
$ cd apache-tomcat-8.0.36
$ ls 
LICENSE        RELEASE-NOTES    bin        lib        temp        work
NOTICE        RUNNING.txt    conf        logs        webapps

Ci sono alcuni file di testo. Per leggerli abbiamo varie opzioni. Scegliamo di usare il less

1
$ less RUNNING.txt

less vi permette di visualizzare la prima parte di un testo e di scorrere in basso e in alto con i tasti freccia. Per uscire e tornare alla shell potete premere il tasto ‘q’. Prima di procedere oltre, facciamo un po' di pratica con i comandi sui file. Impariamo come cancellarli, copiarli e spostarli. Useremo rispettivamente i comandi rm (per rimuovere un oggetto), cp (per copiarlo), mv (per spostarlo)

1
2
3
4
5
6
7
$ rm NOTICE
$ cp RELEASE-NOTES work/
$ mv LICENSE work/
$ ls
RELEASE-NOTES    RUNNING.txt    bin    conf    lib    logs    temp    webapps        work
$ ls work/
LICENSE        RELEASE-NOTES

Nell’esempio abbiamo eliminato il file NOTICE poi abbiamo copiato RELEASE-NOTES nella cartella work/, infine abbiamo spostato il file LICENSE sempre nella cartella work/. Questi comandi funzionano allo stesso modo anche se applicati a directory. Bisogna solo avere l’accortezza di usare il flag -r (ricorsività) se la cartella contiene file o altre cartelle. per copiare la cartella work e tutto il suo contenuto nella cartella temp possiamo scrivere

1
2
3
$ cp -r work/ temp/work
$ ls temp/
work

rm si comporta in modo analogo (il flag -f serve per evitare che ci venga chiesta la conferma per ogni file):

1
$ rm -r -f temp/work

mv invece non ha bisogno del flag -r

1
$ mv work/ temp/

A proposito di mv… anche se sulle prime può sembrare contro-intuitivo, tale comando viene usato anche per rinominare un file

1
$ mv RUNNING.txt running.txt

Il file di nome RUNNING.txt verrà rinominato in running.txt. Approfittiamo di questo esempio per sottolineare il fatto che linux utilizza un approccio case-sensitive per il nome degli oggetti del file-system. Per questo motivo RUNNING.txt e running.txt sono considerati due file diversi e quindi possono coesistere nella stessa directory. Non abbiamo ancora parlato di come fare per modificare un file di testo. Abbiamo a disposizione alcuni ottimi strumenti, molto potenti ma anche piuttosto ostici da imparare. Mi riferisco in particolare a vi e emacs. Essendo questo articolo rivolto a newbie, non affronteremo questi due mostri sacri. Piuttosto rivolgeremo la nostra attenzione ad un text-editor un po' meno sofisticato ma sicuramente più user-friendly per chi è alle prime armi: nano. Usiamo questo strumento per abilitare un utente tomcat alla gestione della manager-gui. Per farlo dobbiamo editare un file di testo, in particolare il file di nome tomcat-users.xml contenuto nella cartella apache-tomcat-8.0.36/conf.

1
2
$ cd conf/
$ nano tomcat-users.xml

Dopo l’esecuzione del secondo comando, troveremo che la command line cambierà aspetto. Verrà mostrata una schermata con il contenuto del file xml e in basso una banda con alcuni shortcut evidenziati. Potete muovervi nel testo usando i tasti di freccia. Posizionatevi alla fine del file e, prima della chiusura del tag , aggiungete le due righe:

1
2
<role rolename="manager-gui"/>
<user username="admin" password="admin" roles="manager-gui"/>

Dagli shortcut in basso potete vedere che per salvare il file dovete premere ctrl+o (^o). Per uscire invece è necessario usare ctrl+x (^x). Proviamo ora a far partire il nostro Tomcat (diamo per scontato che abbiamo la JRE java 8 già installata). Allo scopo dobbiamo eseguire uno script di nome startup.sh che si trova nella directory bin/. Per poter essere eseguito, uno script deve avere i diritti di esecuzione. Possiamo controllare con ls -l che per startup.sh ci sono (i caratteri ‘x’ nel blocco dei permessi):

1
2
$ ls -l startup.sh
-rwxr-xr-x  1 david  admin  1904  9 Giu 15:56 startup.sh

Siamo dunque pronti per avviare il server:

1
2
3
4
5
$ cd bin/
$ ./startup.sh
Using CATALINA_BASE:   /Volumes/Dati/tmp/server/apache-tomcat-8.0.36
[...]
Tomcat started.

Notate che per lanciare un comando dobbiamo specificare anche il path che lo contiene. In questo caso abbiamo usato “./” per indicare come posizione la directory corrente. Tomcat impiegherà qualche secondo a partire. Per controllare lo stato del server, possiamo andare a leggere i log, contenuti nella cartella logs.

1
2
3
$ cd ../logs
$ ls
catalina.2016-06-16.log    host-manager.2016-06-16.log    localhost_access_log.2016-06-16.txt        catalina.out    localhost.2016-06-16.log    manager.2016-06-16.log

Per passare dalla cartella apache-tomcat-8.0.36/bin ad apache-tomcat-8.0.36/logs abbiamo usaro il path ../logs ovvero prima siamo saliti di un livello (con ‘..') e poi ci siamo riposizionati in logs. Il file che ci interessa è catalina.out. Potremmo leggerlo come abbiamo fatto in precedenza, usando less ma questa non sarebbe la soluzione ottimale. Il fatto è che less ci presenta le prime righe del file ma nei log la parte più interessante è alla fine. Fortunatamente Bash ci viene in contro mettendoci a disposizione il comando tail che permette appunto di visualizzare l’ultima parte di un file di testo.

1
2
3
4
5
$ tail catalina.out
[...]
16-Jun-2016 01:20:48.280 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
16-Jun-2016 01:20:48.286 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
16-Jun-2016 01:20:48.288 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 713 ms

Possiamo fare ancora meglio. Specificando il flag -f possiamo chiedere a tail di restare in “ascolto” sul file e di mostrare istantaneamente una qualsiasi aggiunta al testo.

1
$ tail -f catalina.out

Questa funzionalità si rivela particolarmente utile nella fase di debug di una applicazione, perché ci permette di monitorare cosa viene loggato in tempo reale. Per smettere di seguire i log e tornare alla riga di comando si può premere ctrl+c. Per fermare il server tomcat possiamo usare:

1
2
$ cd ../bin
$ ./shutdown.sh

Gestione dei permessi

Abbiamo accennato, in un box, ai permessi attribuibili ad un file. Questi permessi sono modificabili. Prendiamo come esempio il file RELEASE-NOTES.

1
2
ls -l RELEASE-NOTES
-rw-r--r--  1 david  admin  6739  9 Giu 15:58 RELEASE-NOTES

da quanto abbiamo detto in precedenza, il proprietario del file è l’utente david ed il gruppo di appartenenza è invece admin. Il file è leggibile da tutti ma solo l’owner può modificarlo. Il comando chmod ci permette di cambiare queste informazioni. La sua sintassi è semplice:

1
2
3
$ chmod g+w RELEASE-NOTES
ls -l RELEASE-NOTES
-rw-rw-r--  1 david  admin  6739  9 Giu 15:58 RELEASE-NOTES

utilizzando il flag g+w abbiamo chiesto di aggiungere (+) il permesso di scrittura (w) ai soli membri del gruppo (g). Possiamo usare le tre lettere u g o per indicare rispettivamente l’utente proprietario, il gruppo e tutti gli altri. Queste lettere possono eventualmente essere usate insieme. Potremmo ad esempio scrivere:

1
$ chmod ugo+rw RELEASE-NOTES

in modo da settare, in un solo colpo, i diritti di lettura e scrittura (rw) sia all’owner che al gruppo che a tutti gli altri (ugo). Così come possiamo attribuire nuovi permessi, possiamo anche revocarli.

1
2
3
$ chmod go-rw RELEASE-NOTES
$ ls -l RELEASE-NOTES
-rw-------  1 david  admin  6739  9 Giu 15:58 RELEASE-NOTES

nella prima riga abbiamo privato sia il gruppo che gli altri utenti dei permessi sia di lettura che di scrittura sul file. Il proprietario sarà l’unico a poterlo vedere e modificare.

Man pages

I comandi bash sono numerosi e possono essere molto sofisticati. Prendiamo ad esempio il comando find che ci permette di cercare file e cartelle sull’ hard-disk.

1
$ find server/apache-tomcat-8.0.36 -name tomcat-users.xml

Abbiamo chiesto una ricerca per nome del file tomcat-users.xml partendo dalla cartella server/apache-tomcat-8.0.36. Find ha decine di opzioni che permettono di trovare oggetti in base ai più disparati criteri. Potremmo ad esempio voler individuare tutti i file che appartengono ad un certo utente:

1
$ find /home/david -user david

…oppure tutti i file più vecchi di 30 gg…

1
$ find /home/david -mtime 30

…oppure quelli di grandezza superiore a un megabyte ma inferiore a 5 megabyte.

1
$ find /home/david --size +1M --size -5M

I comandi più complessi, possono avere anche decine di opzioni… ovviamente è impossibile ricordarle tutte. Abbiamo però a disposizione un valido strumento da consultare per ottenere informazioni: man. Con man possiamo leggere delle pagine testuali (chiamate man pages) che spiegano tutte le caratteristiche di un certo comando. Se ad esempio volessimo avere informazioni su find potremo scrivere

1
$ man find 

Sullo schermo verrà visualizzato del testo formattato, navigabile con i tasti freccia. Per uscire e tornare alla shell si può premere ‘q’. Purtroppo (o per fortuna) le man pages sono dettagliatissime e proprio per questo un po' difficili da leggere per un neofita.

Conclusioni

Il modo più efficace per imparare Bash è quello di iniziare subito ad utilizzarla. All’inizio anche le azioni più semplici sembreranno ostiche ma perseverando si supereranno velocemente tutte le difficoltà. La shell, allo stato attuale delle cose, non potrà sostituire l’interfaccia grafica, che rimane insuperabile in molti casi. Potrà però affiancarla, dandovi la possibilità di scegliere di volta in volta in che modo eseguire una certa operazione a tutto vantaggio della produttività.

David Ciamberlano