Per gli esercizi dedicati a bash ne propongo uno rielaborato da me qualche mese fa per un corso.
Obiettivo: creare un semplice programma in bash che mostri un menu a schermo e ci permetta di fare delle scelte; in particolare mostrare un elenco di alunni e voti, aggiungere nomi di alunni e relativi voti, svuotare il “database” (in questo caso nient’altro che un file di testo) ed uscire dal programma
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
#!/bin/bash #qui salviamo i dati ELENCO="./alunni.dat" show_menu() { echo echo echo "-- Elenco studenti --" echo "1. Mostra" echo "2. Aggiungi" echo "3. Svuota" echo "q. ESCI" echo -en "> " } do_menu() { i=-1 while [ "$i" != "q" ]; do show_menu read i i=`echo $i | tr '[A-Z]' '[a-z]'` case "$i" in "1") mostra ;; "2") aggiungi ;; "3") svuota ;; "q") echo "Addio, e grazie per tutto il pesce!" exit 0 ;; *) echo "Uhm... non ho capito..." ;; esac done } mostra() { #elenchiamo tutti gli elementi grep -i "" $ELENCO | while read i; do echo "$i" | tr ':' '\t' done } aggiungi() { #aggiungi un elemento echo "Ti chiederemo 2 dati:" echo " - nome, voto" echo echo -en "Nome: " read nome echo -en "Voto: " read voto echo "${nome}:${voto}" >> $ELENCO } conferma() { echo -en "$@" read risp risp=`echo $risp | tr '[a-z]' '[A-Z]'` if [ "$risp" == "Y" ]; then return 0 else return 1 fi } svuota() { conferma "Vuoi cancellare tutti gli studenti? (Y/N) " if [ "$?" -eq "0" ]; then echo -n "" > $ELENCO else echo "CANCELLAZIONE ANNULLATA" fi } do_menu |
Nel nome delle funzioni non c’è niente di speciale, in particolare nelle funzioni showmenu e do_menu che ho chiamato così solo per abitudine, avendolo imparato a mia volta da script in inglese (potremmo dire anche scopiazzato!).
Commentiamo adesso i punti salienti del codice:
Riga 6: show_menu non fa niente di speciale, stampa semplicemente a video una serie di scritte usando echo (quando si usa echo senza una stringa a seguire si ottiene un semplice accapo); l’unico punto veramente interessante è alla riga 15 dove con echo -en ci prepariamo ad acquisire un valore in input. Questo valore in input in realtà viene acquisito dal read nella funzione successiva (riga 24).
Nel caso specifico echo -en vuol dire che passiamo alla funzione echo due parametri
-n evita di aggiungere newline alla fine della stringa, ovvero non manda accapo
-e interpreta eventuali backslash
Per capire meglio come funziona proviamo a scrivere nel terminale le seguenti righe
1 |
echo -en "\tmetti il nome" |
Questo comando darà in output il seguente risultato
1 |
metti il tuo nome |
Il cursore si troverà in attesa alla fine della stringa ed i caratteri \t saranno trasformati in tabulazione.
Se invece scriviamo:
1 |
echo -n "\tmetti il nome" |
Verrà stampato a video:
1 |
\tmetti il tuo nome |
Senza alcuna tabulazione.
Riga 22: cominciamo un ciclo while finché la variabile $i non sarà uguale a “q”.
Riga 24: leggiamo l’input dopo aver lanciato, alla riga precedente show_menu; l’input verrà letto nella variabile $i; dopo aver acquisito $i trasformiamo eventuali maiuscole in minuscole, in modo che sia premendo Q che q si possa uscire dal programma (questo non è ovviamente necessario, ma lo facciamo a titolo di esercizio).
A questo punto usiamo case per verificare la scelta in $i; in caso di qualsiasi scelta fuorché quelle elencate (riga 40) verrà mostrato un messaggio, qui scherzosamente sdubbiato.
Alla riga 36 invece, quando $i è uguale a “q” eseguiamo l’uscita dal programma con un saluto.
A questo punto costruiamo i metodi elencati dentro case.
Riga 48: il metodo mostra fa semplicemente il grep del contenuto del file e poi lo passa ad un ciclo while che legge ogni riga in $i. Il contenuto del file $ELENCO sarà scritto nel modo seguente:
Mario:10
Luigi:9
Anna:7
Ovvero un elenco di nomi separati da : dai voti; uno per riga. Quindi leggendo il file in righe sostituiamo ad ogni : una tabulazione in modo da stamparli a video uno sotto l’altro e con una tabulazione tra nome e voto.
Riga 55: creiamo il metodo per aggiungere nomi e voti; anche qui l’operazione è molto semplice e giochiamo un po’ con gli echo, per ottenere un’interfaccia da terminale decente. Alla riga 65 assembliamo i valori raccolti nelle precedenti due variabili in una singola stringa di testo che scriviamo sul file $ELENCO.
Riga 82: qui svuotiamo l’elenco degli studenti salvati in $ELENCO, semplicemente cancellando il contenuto dell’intero file. Notiamo qui l’uso diverso di >> e >. Il primo appende alla fine del file il contenuto, mentre > sostituisce l’intero contenuto. In questo caso lo sostituisce con una stringa vuota.
Riga 85: qui usiamo il comando $? per prendere l’output dell’ultimo metodo utilizzato, nel caso specifico il metodo conferma (riga 69). Il metodo conferma scrive a video una stringa presa da $@; la variabile $@ prende la lista di tutti gli argomenti passati al metodo, un po’ come fanno $0, $1 ecc per i singoli argomenti; in questo caso significa semplicemente che li prendiamo tutti. Il metodo legge la risposta e la trasforma tutta in maiuscole, in modo tale che Y e y equivalgano entrambi ad una conferma. Se la risposta è tale la funzione restituisce 0, altrimenti 1. Utilizzando $? controlliamo questo valore restituito e se fa 0 allora cancelliamo tutti i dati, se fa 1 annulliamo la cancellazione.
Riga 93: lanciamo l’intero programma.
Riferimenti utili: base di programmazione in BASH