– Foto: Matthew Ratzloff su Flickr.
Il comando per generare automaticamente il nome del file nel formato previsto da Jekyll (o da Wordpress) dal titolo del post presentato alla fine della prima puntata potrà anche essere interessante dal punto di vista didattico ma, diciamolo, è poco pratico per essere utilizzato veramente. Bisogna lanciare il Terminale, andare a cercare il comando da qualche parte, copiarlo e incollarlo nel Terminale, cancellare il titolo preesistente e incollare il titolo del nuovo post su cui stiamo lavorando… Si fa prima a fare tutto a mano nel Finder!
Ma se lo trasformiamo in uno script, cioè in un piccolo programma eseguibile direttamente dal Terminale come un qualunque comando del sistema operativo, le cose diventano improvvisamente molto più interessanti.
Dove vai se l’editor non ce l’hai?
Per lavorare sugli script è fondamentale avere a disposizione un buon editor di testo. In macOS sono già integrati due pesi massimi, emacs
e vi
, eseguibili direttamente dal Terminale tramite i comandi omonimi. Fatevi un favore e non usateli.
Questi due editor, che hanno dato origine ad una vera e propria guerra di religione fra i fan dell’uno e dell’altro programma, sono perfetti per i professionisti, per chi è già esperto di programmazione ed è disposto ad affrontare una fase di apprendimento lunga e piuttosto impervia. Ma per chi è all’inizio e deve concentrarsi sull’imparare le basi e la logica della programmazione, un editor troppo complicato è più che altro un ostacolo ed una distrazione.
Molto meglio installare uno dei tanti editor grafici disponibili per macOS. Fra Atom, BBEdit, TextMate, Visual Studio Code, c’è solo l’imbarazzo della scelta. Sono tutti gratuiti (si, ora anche BBEdit è gratuito, la licenza serve per sbloccare le funzioni avanzate utili per i professionisti), sono tutti di ottima qualità (si, anche un prodotto Microsoft come Visual Studio Code può essere ottimo). Io preferisco usare TextMate e Atom – di quest’ultimo mi piace moltissimo la possibilità di sincronizzare automaticamente le impostazioni, i plugin e i temi fra tutti i computer su cui l’ho installato, che siano Mac o generici PC con Linux o Windows – però BBEdit è perfetto per i file di grosse (o meglio dire enormi) dimensioni come quelli che mi stanno capitando per le mani ultimamente. Mentre Visual Studio Code… beh, Visual Studio Code è stato una vera sorpresa sin dalla prima volta che l’ho usato.
Dalla linea di comando allo script
Lanciamo quindi l’editor che preferiamo e incolliamo l’ultima versione del comando di Terminale visto nella puntata precedente
echo "La privacy al tempo dell'Internet of Things: gran finale" | tr "[:upper:]" "[:lower:]" | sed "s/'/ /g" | sed "s/[[:punct:]]//g" | sed "s/ /-/g"
In questo comando c’è una parte variabile, la stringa “La privacy al tempo dell’Internet of Things: gran finale”, che dobbiamo cambiare ogni volta che vogliamo generare un nuovo titolo, mentre tutto il resto rimane sempre inalterato (a meno di non modificare di proposito il codice).
È sempre consigliabile separare le parti variabili del codice da quelle che rimangono sempre uguali, per evitare di alterare il programma per errore e renderlo inusabile. In questo caso, basta definire una variabile a cui viene assegnata la stringa da elaborare, usata come una specie di segnaposto nel resto del programma, e separare anche visivamente con una o più righe vuote le variabili dal resto del programma. Lo script diventa così
string="La privacy al tempo dell'Internet of Things: gran finale"
echo $string | tr "[:upper:]" "[:lower:]" | sed "s/'/ /g" | sed "s/[[:punct:]]//g" | sed "s/ /-/g"
dove la prima riga definisce la variabile string
, che viene poi usata nel comando vero e proprio.
Da notare che quando si assegna una variabile in bash
non si possono mettere degli spazi prima e dopo l’operatore di assegnazione =
. In altre parole il nome della variabile, l’operatore e il valore della variabile devono essere scritti tutti attaccati. Inoltre, quando si usa la variabile nello script bisogna sempre anteporre il prefisso $
e scriverla come $string
. Sono due particolarità di bash
di cui è facile dimenticarsi quando si è abituati ad usare altri linguaggi di programmazione, a me succede anche troppo spesso.
Guardiamo ora la seconda riga. Nel comando originale da Terminale l’abbiamo scritta tutta di seguito, usando l’operatore |
per trasferire il risultato di un comando al comando immediatamente successivo, che lo usa come dato di ingresso da elaborare. È una pratica che evita la creazione di troppe variabili, magari usate solo una volta, che è diventata popolare di recente in R, un linguaggio di programmazione specializzato nell’analisi statistica dei dati.
Personalmente la trovo una pratica poco lungimirante. Sarà anche comoda nel momento in cui sviluppiamo un programma, ma rende molto più difficile capire in un secondo momento quello che fa lo script. Ormai la memoria dei computer è gigantesca, possiamo benissimo sprecarne un po’ per definire qualche variabile in più.1
Una versione riveduta del programma precedente, nella quale i risultati di ciascuna fase di elaborazione vengono salvati in una variabile diversa, può quindi essere
string="La privacy al tempo dell'Internet of Things: gran finale"
lowercase=$(echo $string | tr "[:upper:]" "[:lower:]")
del_apostr=$(echo $lowercase | sed "s/'/ /g")
del_punct=$(echo $del_apostr | sed "s/[[:punct:]]//g")
fix_spaces=$(echo $del_punct | sed "s/ /-/g")
converted_string=$fix_spaces
echo $converted_string
Qui devo ammettere di avere esagerato. Se la prima versione scritta tutta d’un fiato era difficile da leggere e da capire, usare una variabile diversa per ogni passo del programma è altrettanto estremo. Un buon compromesso potrebbe essere
string="La privacy al tempo dell'Internet of Things: gran finale"
fix_string=$(echo $string | tr "[:upper:]" "[:lower:]")
fix_string=$(echo $fix_string | sed "s/'/ /g")
fix_string=$(echo $fix_string | sed "s/[[:punct:]]//g")
fix_string=$(echo $fix_string | sed "s/ /-/g")
converted_string=$fix_string
echo $converted_string
in cui si usa una variabile (string
) per la stringa da elaborare, un’altra (fix_string
) per conservare i risultati intermedi ed infine un’ultima variabile (converted_string
) per il risultato finale del programma.
Se si guardano attentamente le due ultime versioni dello script, si nota che ho continuato ad usare l’operatore |
per inviare a sed
o a tr
la stringa da elaborare. Non è una contraddizione rispetto a quanto dicevo prima. Una cosa è scrivere una sequenza di quattro, cinque o più comandi collegati uno all’altro a formare una catena di montaggio inestricabile, un’altra è utilizzare ripetutamente una struttura ben definita e riconoscibile come echo $... | tr "..."
oppure echo $... | sed "..."
.
Del resto non ci sono alternative: sia sed
che tr
sono fatti per operare su un file oppure in modo interattivo nel Terminale (si scrive una stringa nel Terminale, si preme Invio e sed
o tr
la elaborano, stampano il risultato e si mettono in attesa di una nuova stringa finché non li interrompiamo premendo CTRL-D) e l’unico modo per obbligarli a lavorare da programma e usare echo
per fornirgli il dato in ingresso già bello e pronto.
Al nostro script mancano ancora due cosette per essere quasi comodo da usare, ma questo sarà l’argomento della prossima puntata.
-
A meno naturalmente di non avere dei grossi limiti di memoria, come succede quando si scrivono programmi per dispositivi embedded o dell’IoT, oppure di dover scrivere del codice molto efficiente per applicazioni ultrasofisticate. Ma chi è alle prese con questi problemi non ha bisogno di leggere questi articoli. ↩