Su HTMLit è già presente una buona guida per l’argomento che ci apprestiamo a trattare tuttavia risulta piuttosto corposa. I fini generali che ci prefiggiamo in questo percorso di apprendimento sono diversi pertanto presenteremo Bash in maniera più stringata focalizzandoci sugli elementi essenziali. Dovete immaginare questa puntata della nostra guida come un “one shoot” per raggiungere un livello di comprensione beginner del bash scripting al fine di acquisire le competenze necessarie a implementare semplici script in un tempo contenuto. Per un ulteriore approfondimento rimandiamo di conseguenza alla guida già presente sulla piattaforma nonché reperibile a questa url.
Cosa è uno script?
Ora che vi è chiaro il concetto di background, trattato nel precedente capitolo, sapete che una serie di comandi può essere inviata in esecuzione anche senza controllo diretto e che uno o più comandi possono essere temporaneamente interrotti quindi fatti ripartire. Ora potrete organizzare sequenze di comandi in un file definito script. Questi è un file di testo che istruisce comandi da svolgere rispettando un ordine oppure saltando da a un punto specifico a un altro punto di una sequenza di comandi preimpostati in risposta a determinate situazioni esterne che influenzano il flusso di esecuzione. Ovviamente i comandi in questione possono essere svolti per un certo numero di volte sfruttando operatori ciclici. Uno script non è quindi nulla di esotico o complesso da capire, è essenzialmente un algoritmo stilato in linguaggio comprensibile sia per il sistema operativo sia per l’autore. Una volta implementato il secondo lo affida al primo per ottenerne l’esecuzione.
Cosa è la Bash?
La Bash è la shell (ovvero l’interfaccia testuale) più diffusa e utilizzata in ambiente Linux. Come sapete Linux discende da Unix di conseguenza la shell bash prende spunto dalla sua omologa presente in quest’ultimo ovvero la sh shell. Esistono svariate shell per Linux, noi ci concentreremo su Bash proprio perché è quella con cui è più probabile avere a che fare. In ogni caso, appresi i rudimenti della bash shell, sarà per voi abbastanza facile utilizzare altre shell. Bash è un acronimo di bourne again shell che a sua volta è un gioco di parole a metà strada tra “shell rinata” e “un’altra shell Bourne” in riferimento a Stephen Bourne ovvero l’autore della sh shell.
Uno sguardo a qualche script
Quando si incontra per la prima volta qualcuno è sempre bene aprire la conversazione con una cortese formula di saluto. Per tradizione l’approccio iniziale a un nuovo linguaggio avviene attraverso un saluto al mondo. Bash è un linguaggio. Ecco quindi il primo script bash con cui vi confronterete:
#!/bin/bash
echo "Un saluto a tutti da HTML.it"
exit 0
Utilizzando un editor di testo (ad esempio nano) inserite queste righe in un file.
Poi fatelo partire adoperando il comando bash seguito dal nome del file.
Ripetete questa procedura per ogni esempio riportato in questo testo.
Torniamo allo script subito sopra, ciò che otterrete dalla sua esecuzione è il testo tra doppi apici.
Avete già incrociato il comando echo che restituisce a schermo un testo o il valore di variabili.
Osserviamo quindi il primo carattere della prima riga: “#”. Ogni riga che inizia con # (cancelletto) per Bash è un commento esplicativo da non interpretare come comando. Di norma uno script bash inizia con #! seguito dalla path assoluta del binario di bash.
l’ultima riga è un exit code. Un exit code è un messaggio in cui segnaliamo che il codice è giunto a quel punto e che, secondo le previsioni dell'implementare, l’esecuzione si è svolta in un modo specifico. Esistono 255 exit code, Potrete implementare diversi punti di uscita in risposta a ciò che accade nel vostro codice. Su internet è possibile reperire tabelle esaustive per utilizzi specifici ma le exit più comuni sono 0 e 1 in cui la seconda identifica una condizione di uscita per errore generico mentre la prima comunica una esecuzione regolare.
Osserviamo un ulteriore script.
#!/bin/bash
#Uno script per ottenere le dimensione totale di un file o directory
echo "Di quale file o directory desideri conoscere la dimensione?"
read filedirectory
du -hs $filedirectory
exit 0
Questo script introduce la lettura di un valore esterno attraverso read e lo passa, seguito dal segno “$” a un comando. Quando desideriamo utilizzare un valore assegnato a una variabile possiamo, infatti, richiamarlo in questo modo. Qui lo adoperiamo insieme al comando du che restituisce la quantità di disco utilizzata dall’argomento.
Ecco il risultato.
fprincipe@html1:~$ bash 2.sh
Di quale file o directory desideri conoscere la dimensione?
/home/fprincipe
396K /home/fprincipe
/home/fprincipe
fprincipe@html1:~$
Torniamo sulle variabili. E’ bene sapere che se in uno script bash utilizziamo una variabile questa di default è gestita come una stringa di testo. E’ comunque possibile dichiararla quale appartenente a tipologie differenti attraverso declare. Se usiamo declare -i la variabile sarà considerata un numero intero e gestita opportunamente. E' possibile anche inizializzare a un valore specifico adoperando “=”. Nello script a seguire eseguiamo una somma ciclica che si arresta quando il numero da sommare è 0 quindi restituisce il risultato finale. Come abbiamo detto è, infatti, possibile eseguire azioni ripetitive attraverso specifici operatori. Uno di essi è il while che ripete il codice fra do e done sino a quando la condizione racchiusa nelle parentesi quadre è vera. Immediatamente dopo lo script in questione troverete una tabella che riassume i possibili confronti da abbinare a questo operatore così come a quello che verrà presentato subito in calce alla tabella.
#!/bin/bash
#Una somma progressiva
declare -i N1=1
declare -i S1=0
while [ $N1 -ne 0 ];
do
echo "inserisci il numero da sommare:"
read N1
S1=$S1+$N1
echo "Somma parziale: " $S1
done
echo "Somma finale: " $S1
exit 0
Confronto | Significato |
a -eq b | "a" è uguale a "b" |
a = b | "a" è uguale a "b" per variabili contenenti stringhe |
a -ne b | "a" non è uguale a "b" |
a != b | "a" non è uguale a "b" per variabili contenenti stringhe |
a -gt b | "a" è maggiore di "b" |
a -lt b | "a" è minore di "b" |
a -ge b | "a" è maggiore o uguale a "b" |
a -le b | "a" è minore o uguale a "b" |
-n a | "a" non è null o void |
-z a | "a" è null o void |
L’operatore ciclico inverso è until, sostituendo infatti until a while otterrete il comportamento logico opposto infatti until esegue le operazioni contenute tra do e done solo quando la condizione valutata è falsa.
Ora passiamo all'operatore ciclico più conosciuto ovvero il for. Esegue ciò che è stato inserito fra do e done per tutti gli elementi di una lista. Vediamolo in un due differenti esempi.
#!/bin/bash
declare -i count=0
for i in *.sh
do
count=$count+1
done
echo "In questa directory ci sono $count file sh."
exit 0
#!/bin/bash
for ((i=1; i<=9; i++))
do
echo "All work and no play makes Jack a dull boy."
done
exit 0
Nel primo caso il for “conta” i file con estensione "sh" presenti nella directory in cui è stato lanciato, nel secondo ripete un testo per un certo numero di volte. Osserviamo il secondo rigo di questo esempio. Nella doppia parentesi tonda abbiamo in un unico colpo dichiarazione e inizializzazione del contatore, valore di uscita dal ciclo, operazione di incremento del contatore.
Ci lasciamo con un ultimo esempio che introdurrà le strutture di controllo. Prima ne forniremo una rapida spiegazione. Il comando if effettua una sterminata quantità di controlli condizionali su file, stringhe e variabili, con -d e -e controllerete rispettivamente l’esistenza di una directory e di un file. In questo script usiamo anche il comando case che consente di creare dei blocchi di codice che saranno eseguiti qualora la variabile di riferimento assuma determinati valori. Ogni blocco inizierà con le opzioni di attivazione separate dalla barra verticale “|” (pipe). La parantesi tonda chiusa termina la dichiarazioni delle opzioni di attivazione mentre ogni blocco a queste relativo termina con il doppio punto e virgola. Un segmento di codice su cui agiscono if o case è sempre concluso scrivendo gli operatori alla rovescia quindi fi e asac.
#!/bin/bash
#Controlla l'esistenza di diretory o file
echo "Scegli fra (d)irectory e (f)ile e premi invio"
read scelta
case $scelta in
d | d )
echo "Scrivi la path assoluta della directory"
read pathdirectory
if [ -d "$pathdirectory" ]; then
echo "La directory" $pathdirectory" esiste."
else
echo "La directory" $pathdirectory" non esiste.";
fi
;;
f | F )
echo "Scrivi la path assoluta del file"
read pathfile
if [ -e "$pathfile" ]; then
echo "Il file" $pathfile" esiste."
else
echo "il file" $pathfile" non esiste.";
fi
;;
esac
exit 0