Se sei felice e tu lo sai lancia uno script

konsole_48Potreste pensare che ci ho preso gusto a trasformare le canzoncine per bambini in script bash, e tutto sommato avreste ragione. È strano e divertente al tempo stesso accostare due ambiti così diversi, che tuttavia presentano alcuni aspetti favorevoli a questa particolare scelta. Le canzoni per bambini hanno infatti testi semplici, in cui è facile riconoscere uno schema basato su un numero ridotto di frasi o parole da ripetere, sostituire, alternare e così via, che ben si prestano ad essere “tradotti” in codice da eseguire. A me d’altronde interessa imparare qualcosa dello scripting bash (chiariamo una volta per tutte: i miei post sull’argomento non sono in alcun modo un “corso”), ma per farlo ho bisogno di un obiettivo, un semplice problema da risolvere con i mezzi offerti dalla shell. Ed ecco che il mondo delle filastrocche ed il mondo del “terminale”, che sembravano tanto distanti, inaspettatamente trovano un punto di incontro.

Dunque, pur di imparare potrei adottare anche soluzioni non particolarmente efficienti o eleganti. Al contrario, potrei “forzare” l’uso di alcuni costrutti solo per sperimentare qualcosa di nuovo, rinunciando ad alternative più semplici ma magari già usate altrove. Non sarei felice di limitare le mie scelte a poche, usuali istruzioni. Io invece voglio essere felice di scrivere uno script, per quanto inutile…😉

Ed allora, su!, tutti in coro: “Se sei felice e tu lo sai batti le mani!”


Sono felice

Riportare per intero la canzone prenderebbe tempo e tanto spazio, a dover scrivere e riscrivere tutte le azioni da fare, e manda un bacio, e batti i piedi, e fai un carpiato con triplo avvitamento: sono felice, ma non sono mica fesso!😆 Sono anche un tantinello nerd quando mi applico e quindi ho messo insieme uno script che faccia il lavoro per me.

Sono partito dal ridurre la filastrocca alla sua struttura:

  1. Se sei felice… [fai un’azione] (ripeti 2 volte)
  2. Se sei felice… e mostrarmelo… [frase senza varianti]
  3. Se sei felice… [elenca l’azione corrente e le precedenti in ordine inverso]

La lista di azioni da “cantare” è lasciata alla fantasia di voi bambin(on)i, tanto lo script è congegnato in modo da digerire qualunque sfida sconsiderata vogliate lanciare ai vostri compagni di gioco: anche “Se sei felice e tu lo sai buttati col paracadute da 39000 m di altezza“.

Ed ecco lo script che ricrea la struttura della canzoncina, con il consueto mucchio di commenti:

#!/bin/bash
################################################################
# Se sei felice e tu lo sai lancia uno script                  #
# Ver. 0.1 - 05/mag/2013                                       #
# Autore: Man from Mars (https://extendedreality.wordpress.com) #
# Rilasciato sotto licenza CC BY-NC-SA v. 2.5                  #
# http://creativecommons.org/licenses/by-nc-sa/2.5/it/         #
################################################################
azione=("batti le mani"
"batti i piedi"
"schiocca le dita"
"manda un bacio"
"fai \"ciao ciao\""
"lancia uno script")
sesei="Se sei felice e tu lo sai"
mostra="e mostrarmelo vorrai"
count=0
passo=0.5
echo -e ${sesei^^}\\n${sesei//?/#}\\n
while [ $count -lt ${#azione[@]} ] # inizio while
do
for ripeti in 1 2 # inizio for (1)
do
echo -e $sesei ${azione[$count]}
sleep $passo
done # fine for (1)
echo $sesei $mostra
sleep $passo
for reverse in `seq $count -1 0` # inizio for (2)
do
if [[ $reverse = $count ]] # inizio if
then
echo $sesei ${azione[$reverse]}
else
echo -e ${sesei//[[:print:]]/\\040} ${azione[$reverse]}
fi # fine if
sleep $passo
done # fine for (2)
echo -e '---'\\n
sleep $passo
count=$(($count+1)) # incremento contatore while
done # fine while
exit

Il risultato, o meglio “l’output” che fa più figo, dovrebbe essere familiare a molti:

SE SEI FELICE E TU LO SAI
#########################

Se sei felice e tu lo sai batti le mani
Se sei felice e tu lo sai batti le mani
Se sei felice e tu lo sai e mostrarmelo vorrai
Se sei felice e tu lo sai batti le mani
---

Se sei felice e tu lo sai batti i piedi
Se sei felice e tu lo sai batti i piedi
Se sei felice e tu lo sai e mostrarmelo vorrai
Se sei felice e tu lo sai batti i piedi
                          batti le mani

[...]
Se sei felice e tu lo sai lancia uno script
Se sei felice e tu lo sai lancia uno script
Se sei felice e tu lo sai e mostrarmelo vorrai
Se sei felice e tu lo sai lancia uno script
                          fai "ciao ciao"
                          manda un bacio
                          schiocca le dita
                          batti i piedi
                          batti le mani
---

Nella strofa finale mi sono permesso una piccola “personalizzazione”.🙂


Come essere felici

Purtroppo parlo solo dello script, non ho la ricetta per la vita:mrgreen: Più modestamente, quindi, vediamo cosa sono riuscito ad infilare stavolta nelle righe di codice.

Righe 1 e 2-8: Ho già chiarito nel precedente post la diversa funzione di “#!” e “#“. Ho quindi sfruttato i commenti per inserire una breve sezione informativa con titolo, versione, autore, licenza dello script, utile per chi volesse riutilizzarlo in futuro e (come prevede la Creative Commons) citare la fonte. Vanità a parte, è una pratica comune nel caso di script abbastanza complessi.

Righe 9-14: La prima novità: un “array” di valori. L’array è una lista, un insieme di valori raggruppati sotto un nome comune, al pari di una variabile. Normalmente i valori sono separati da spazi (o anche “a capo”, come ho scelto di fare), tuttavia la presenza di spazi nei valori stessi richiede l’utilizzo delle virgolette per racchiudere le stringhe e non generare confusione. In pratica un array dichiarato come
animali=(il cane la mucca)
sarebbe considerato composto da 4 valori (il, cane, la, mucca), mentre
animali=("il cane" "la mucca")
ne avrebbe solo 2, presumibilmente quelli giusti😉

Per richiamare uno specifico valore dell’array si utilizza un indice, a partire da 0 (non da 1, attenzione!). Nell’array “azione” dunque azione[0] è “batti le mani” (il primo della lista), azione[5] è “lancia uno script” (sesto ed ultimo valore).

La sintassi esatta per riferirsi ad un valore è ${nomearray[indice]} mentre la dimensione dell’array (numero di valori contenuti) si ottiene con ${#nomearray[@]}. Analogamente all’assegnazione di valori a variabili, si può scrivere “nomearray[indice]=valore” per assegnare o sostituire il valore di un elemento.

Da notare anche l’escaping delle virgolette (\”) nel penultimo valore, che permette di includerle nella stringa senza che siano considerate come delimitatori della stessa.

Righe 15-18: Assegnazione di valori ad alcune variabili: le due stringhe “sesei” e “mostra” e due valori numerici che spiegherò tra un istante. Cose utili ma niente di nuovo qui.

Riga 19: Due trucchetti che ho imparato sfogliando la pagina man di bash. La shell è capace di operare direttamente alcune trasformazioni sui valori delle variabili, specialmente quando si tratta di stringhe. Sfogliate le pagine di man bash per maggiori dettagli (vale come consiglio in generale!).

Nelle prime 2 righe dell’output ho voluto creare una sorta di titolo, prima convertendo tutto in maiuscolo il contenuto della variabile sesei (${sesei^^}) e successivamente sostituendo un “#” a tutti i caratteri che la compongono (${sesei//?/#}). Quest’ultima sintassi in generale si scrive come
${variabile//vecchio/nuovo}
mentre il “?” è un cosiddetto carattere “jolly” (wildcard) che permette di indicare ogni singolo carattere della stringa.

Righe 20-42: Comincia la vera “ciccia” dello script. Tutte le istruzioni da eseguire sono racchiuse (tra i consueti do... e ...done) in un ciclo while (“mentre”). Tale ciclo continua ad eseguire il blocco di codice fintanto che è verificata la condizione imposta.

In questo caso ho semplicemente imposto che il ciclo sia eseguito finché il valore di count è minore (“-lt” è “less than”) della dimensione dell’array. Più in generale, poiché il while è controllato da una condizione e non da una lista di valori, si può ottenere l’esecuzione ripetuta di un blocco di istruzioni per un numero di volte non fisso, a differenza del ciclo for.

Riga 22: Dentro il while c’è un altro ciclo (più di uno, in effetti), come in una matrioska. Quando più cicli sono innestati l’uno nell’altro, l’esecuzione parte da quelli più interni e procede verso l’esterno, ed i cicli interni si dicono “nidificati”. Con riferimento all’immagine, per completare il “Ciclo 3” si dovrà eseguire prima il “Ciclo 4” e le successive istruzioni.

cicli_nidificati

Esempio di cicli nidificati

Nello specifico, per ripetere 2 volte la stringa sesei uso la variabile ripeti come semplice contatore che scorre una lista appunto di 2 valori. Non è necessario che tali valori siano numerici o disposti in ordine in quanto servono solo da “segnaposto” per il numero di ripetizioni. Avrebbe avuto lo stesso effetto scrivere, ad esempio: for ripeti in pippo ciccio.

Riga 24: Finalmente gli array all’opera. Si deve elencare qui l’azione della strofa corrente, dunque ${azione[$count]}, preceduta da “Se sei felice…“, stringa convenientemente contenuta nella variabile sesei.

Riga 28: Per cadenzare la visualizzazione ho aggiunto un’istruzione sleep dopo ciascun echo. La variabile passo definita inizialmente definisce la lunghezza della pausa, con il vantaggio di poterne cambiare il valore modificando una sola riga piuttosto che ogni istruzione sleep.

Riga 29: Devo ora elencare in ordine inverso tutte le azioni da quella corrente fino alla prima, ovvero gli elementi dell’array dal corrente fino al primo (indice 0, non 1!). Genero la sequenza inversa di indici con il comando seq che, si intuisce dal nome, serve esattamente a questo. Il passo della sequenza sarà -1 per andare a ritroso (opzionale, default 1), il termine finale 0. La particolarità sta nel fatto che tale comando è racchiuso tra apici inversi (“`” detti “backtick”) e crea la lista per il for. Con questa notazione, utile in moltissimi casi, si indica che l’output del comando racchiuso tra backtick deve essere “passato” come argomento al resto dell’istruzione:

seq 3 -1 0 → 3 2 1 0
for i in `seq 3 -1 0` → for i in 3 2 1 0

Righe 31-36: Un altro trucco, un’altra manipolazione di variabili. Mentre il ciclo for sta gestendo la lista di valori da visualizzare, l’if...then...else “capisce” se mi serve la frase completa o no. Nel secondo caso opero nuovamente una sostituzione di caratteri come ho fatto all’inizio, visualizzando il valore di sesei con tutti i caratteri sostituiti da spazi, allineando così “a modino” le azioni, perché anche l’occhio vuole la sua parte.

Due cose sono importanti nella sintassi di manipolazione della stringa:

  1. i caratteri da sostituire sono individuati dalla “classe” [:print:] ovvero “tutti i caratteri stampabili”; ci sono diverse classi (tutte le lettere, tutti numeri, tutte le maiuscole, etc.) definite nello standard POSIX
  2. il carattere sostitutivo “spazio” è indicato con il suo valore ottale “040”, secondo la tabella Unicode. Questa notazione consente di utilizzare facilmente tutti i caratteri del set Unicode, soprattutto quelli non presenti su tastiera (pensate a cuoricini, segni grafici, simboli matematici, etc.). Se devo essere sincero, ho scelto questa strada anche perché non ho trovato un modo, che di sicuro c’è, di fare l’escaping dello spazio😳 (apici, virgolette e \ non hanno funzionato!). Meglio così, ho imparato qualcosa di nuovo…

Le poche righe restanti non fanno niente di notevole quindi confido nella dedizione dei lettori per comprenderne il significato.

Quindi se sei felice e tu lo sai, lancia lo script. Se non sei felice, lancialo lo stesso che magari ti aiuta a farti due risate😀

Io intanto vado a giocare in cortile con la maestra. Saluti e alla prossima canzoncina… ehm… al prossimo script!


P.s.: Per favore, segnalatemi eventuali refusi nello script o nella formattazione. Ogni tanto WordPress fa le bizze quando si scrivono righe di codice. Denghiù🙂

Informazioni su Man from Mars

https://extendedreality.wordpress.com/

  1. Ralph Magpie

    Ecco, si inizia così e poi si finisce in tarda età a giocare con le scatoline nere piene di pinguini😦
    Ravvediti finché sei in tempo … In alternativa se proprio devi aumentare la casistica dei neuropatici vieni tra i serpenti, i pitoni danno tanta soddisfazione e come neuropatizzano loro …

    Mi piace

  2. Pingback: S.S.S.S.S.S.S.S.: Semplici Script Senza Senso Supportati Sonoramente dal Suonatore Silvestri | Extended Reality

Dimmi che ne pensi o fai "Ciao ciao!" con la manina // Share your thoughts or just say "Hello!"

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: