giovedì 26 novembre 2015

Tutorial Bash: realizzare un countdown a Star Wars Episodio 7

Un piccolo tutorial per chi vuole imparare un po' di Bash o per chi semplicemente è un grandissimo fan di Star Wars e sta contando i secondi che mancano all'uscita de "Il risveglio della forza".
Vediamo insieme come creare uno script che visualizzi il countdown funzionante alla fatidica data di uscita del film.




In realtà il countdown può essere usato per qualunque data vogliate, in questo caso ho usato il tema Star Wars ma voi potete modificarlo a piacere. 
Lo script completo e già pronto lo trovate in fondo alla guida!

Cos'è il Bash

Per chi non lo sapesse, Bash è un ambiente testuale che trovate di default nei sistemi operativi Unix e Unix-like (quindi anche su Mac) ma è installabile a parte anche sui sistemi Windows. Tramite questa shell è possibile eseguire una svariata serie di comandi e, soprattutto, realizzarne di personalizzati. Proprio quello che andremo a fare ora.

Cosa vogliamo fare

Anche se si tratta di un semplice script, consiglio sempre di partire buttando giù l'idea generale, l'algoritmo insomma.
Quello che vogliamo è, data la data e ora attuale, calcolare in tempo reale quanto manca ad una determinata data e stamparlo a schermo. Il tutto magari abbellito da una bella scritta in ASCII art che io personalmente adoro.

Scriviamo il codice 

Per prima cosa, prendiamo la data finale da raggiungere. Nel nostro caso è il 16 Dicembre 2015 (io andrò a vederlo alle 19.30 al cinema quindi metterò quello come orario). Usiamo il comando date:

target=`date +%s --date='16 December 2015 19:30:00'`

Il comando date che, se usato da solo ci stampa la data e ora attuale. Nel nostro caso gli abbiamo specificato la data di uscita del film e salvato il tutto in una variabile chiamata target.
Ora, dobbiamo calcora la differenza tra questa data e la data attuale.
Per farlo, usiamo il comando expr che ci permette di valutare e calcolare automaticamente un'espressione.

source=`date +%s` diff=`expr $target - $source`
Abbiamo salvato la data attuale nella variabile source e calcolato la differenza tra target e source. Il tutto viene salvato nella variabile diff. Notate che quando dovete usare le variabili dovete metterci davanti il dollaro $.
Questo però non basta, perchè noi vogliamo specificatamente i giorni, le ore, i minuti e i secondi.
Andiamo quindi a calcolarli uno ad uno salvandoli in delle variabili, sempre usando expr per ottenere il risultato delle operazioni.
d=`expr $diff / 86400`
h=`expr \( $diff % 86400 \) / 3600`
m=`expr \( \( $diff % 86400 \) % 3600 \) / 60`
s=`expr $diff % 60`
Inutile dirvi come si calcolano giorni, ore eccetera, è abbastanza esplicativo di suo.
Non ci resta che stampare a video il nostro risultato.
Per farlo usiamo il comando echo:

echo  "======== The Force Awakens in $d Days $h Hours $m Minutes $s Seconds ========" 
Semplicemente, quello scritto tra gli apici verrà visualizzato a schermo. Notate che le variabili sono state inserite con il $ e al loro posto verrà inserito il valore calcolato precedentemente.
C'è un problema però. Il countdown così non è interattivo! Stampa una volta e termina.
Per risolvere dobbiamo ricalcolare ciclicamente il valore delle variabili. Mettiamo quindi tutto dentro ad un bel ciclo while.
while true; do
    source=`date +%s`
    diff=`expr $target - $source`
    d=`expr $diff / 86400`
    h=`expr \( $diff % 86400 \) / 3600`
    m=`expr \( \( $diff % 86400 \) % 3600 \) / 60`

s=`expr $diff % 60`     echo  "======== The Force Awakens in $d Days $h Hours $m Minutes $s Seconds ========" 
Ho semplicemente aggiunto la prima riga contentente il loop. Questa riga dice: finchè è vero (quindi per sempre, vero è sempre vero) esegui le operazioni scritte dopo "do".
Non abbiamo ancora finito però. Perchè? Perchè così vi stampa all'infinito il messaggio in echo creandone una serie ripetuta che vi riempirà tutto lo schermo.
Quello che vogliamo è stampare con echo sempre sulla stessa riga.
Per farlo modifichiamo l'istruzione echo sostituendola con questa:

echo -n "======== The Force Awakens in $d Days $h Hours $m Minutes $s Seconds ========" \\r
-n dice di non andare a capo in una nuova riga dopo aver stampato, che combinato con \\r permette di rimanere sulla stessa riga. Il carriage return, o \r, riporta infatti il cursore all'inizo della linea, quindi la prossima volta che stamperemo saremo sulla stessa linea e all'inizio di questa.
Un'ultima miglioria. Vogliamo che il ciclo termini e il programma esca alla pressione del tasto q (che sta per quit).
Aggiungiamo quindi dopo l'echo il comando read:

read -t 1 -n 1 key
    if [[ $key = q ]]; then
    echo ''
        break
    fi
Il comando read dice alla shell di rimanere in attesa della pressione di un tasto. Noi però non vogliamo che la shell si blocchi ma che continui il ciclo. L'opzione -t 1 imposta un timeout di un secondo in modo da sbloccarlo subito e -n 1 dice di accettare al massimo un carattere, la nostra "q" appunto.
Subito dopo diciamo che, se il tasto premuto è qu, allora break. L'istruzione break fa terminare il ciclo e nel nostro caso anche il programma, visto che dopo non ci sono altre istruzioni.
Bene il countdown è pronto!!
Ma non avevo parlato di ASCII art?! Ma certo che si! E allora vi allego un bel logo dedicato a Star Wars The Force Awakens da stampare all'inizio del countdown per abbellirlo un po'! Lo trovate nel file contenente lo scipt già completo e funzionante che vi allego qui sotto. Apritelo con un editor di testo e troverete tutto il codice.
Per eseguirlo scaricatelo, aprite una shell bash e spostatevi nella cartella dove l'avete salvato con cd.
Cambiategli i permessi a 755 con chmod e infine digitate ./nomescript per eseguirlo!

Ecco il countdown da scaricare: countDownEp7
Il risultato finalè sarà la nostra bella scritta in ASCII art e in fondo il countdown interattivo:


Per qualunque dubbio non esitate a scrivermi!!


Nessun commento:

Posta un commento