Script per tutti i giorni: lo script è il comando

Nelle puntate precedenti abbiamo visto come scrivere dei semplici script in bash o in awk che risolvono un problema assai specifico, è vero, ma che possono anche costituire una buona base di partenza per affrontare argomenti più complessi (i link alle puntate precedenti si trovano alla fine dell’articolo).

In particolare, nella terza puntata abbiamo imparato come rendere i nostri script quasi indistinguibili dai normali comandi del Terminale: (1) si aggiunge in testa allo script lo shebang, cioè la sequenza di caratteri #!, seguita dal percorso completo al programma da utilizzare per eseguire lo script,1 (2) si usa il comando chmod per rendere lo script eseguibile (almeno) all’utente attuale del Mac,

$ chmod u+x nomescript

dove nomescript è il nome generico dello script che vogliamo rendere eseguibile (ad esempio lo script convert_title.sh della terza puntata).

Il “quasi” di prima dipende dal fatto che, anche con queste modifiche, ogni volta che eseguiamo lo script dobbiamo indicare esplicitamente la directory dove si trova. Ad esempio, se ci siamo spostati con cd nella directory che contiene nomescript, per eseguirlo script dobbiamo scrivere

$ ./nomescript

premettendo quindi al nome dello script il percorso (./) alla directory corrente.

Invece, quando eseguiamo uno dei comandi del sistema operativo, ci basta scrivere il nome del comando nel Terminale e il sistema operativo (o più precisamente la shell che stiamo usando, che in genere è bash)2 va a cercare il programma sul disco rigido e lo esegue senza troppi problemi.

Qual’è il meccanismo che permette alla shell di sapere in quale directory si trovano i comandi che eseguiamo nel Terminale? Esiste un modo per replicare questo comportamento anche per i nostri script, rendendoli praticamente indistinguibili dai comandi intrinseci del sistema operativo?

Variabili di ambiente

In realtà non c’è niente di sofisticato o di particolarmente intelligente in quello che fa la shell. La chiave di tutto sta nelle variabili di ambiente di bash, delle variabili speciali usate fra l’altro per specificare le impostazioni di lavoro della shell. Se lanciamo il Terminale ed eseguiamo il comando

$ env

otterremo un lungo elenco con tutte le variabili di ambiente definite da bash, che per convenzione vengono scritte in maiuscolo. Fra queste spiccano HOME, che definisce il percorso alla cartella Home dell’utente che sta usando il Mac, USER che riporta il nome account (o nome breve) dell’utente, e PWD che contiene il percorso alla directory in cui ci troviamo (percorso che, come già visto, si può ricavare con il comando pwd, ma guarda la combinazione).

Se siamo interessati solo ad una particolare variabile di ambiente, possiamo stamparla con echo seguito dal nome della variabile di ambiente, che però deve essere preceduto dal simbolo $. Ad esempio

$ echo $HOME

stampa nel Terminale il valore della variabile di ambiente HOME.

Fra tutte le variabili di ambiente elencate da env, quella che ci interessa di più in questo momento è PATH, che contiene una serie di percorsi di directory separati dal simbolo :. Nella configurazione di default il valore del PATH è

$ echo $PATH
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Shell e PATH

È proprio il PATH che permette alla shell di trovare da sola i comandi di sistema. Ogni volta che eseguiamo un comando nel Terminale, la shell lo cerca nelle directory indicate nel PATH, esaminandole una dopo l’altra nell’ordine in cui sono scritte. Se trova il comando lo esegue immediatamente, senza preoccuparsi di esaminare le directory successive, altrimenti dà un errore di command not found.

Di conseguenza, l’ordine in cui sono elencati i percorsi nel PATH è importante. Questa particolarità può essere sfruttata per sostituire un comando del sistema operativo con una versione più recente, senza però cancellare il comando originale: se il comando originale è situato in /usr/bin o in /bin, basta installare la versione aggiornata in una directory del PATH che precede queste due directory, come ad esempio /usr/local/bin (che nei sistemi Unix serve proprio per installare il software “locale” non gestito direttamente dal sistema operativo).3

La seconda conseguenza è che, se modifichiamo il PATH aggiungendo altre directory in testa o in fondo all’elenco originale, possiamo obbligare la shell a cercare i comandi anche in queste nuove directory non presenti nella configurazione di default. Che è proprio quello che ci serve.

Prima di andare avanti una avvertenza FONDAMENTALE. Possiamo aggiungere senza troppi problemi delle nuove directory al PATH di default, ma non dobbiamo MAI MAI MAI rimuovere le directory presenti nella configurazione originale del PATH, in particolare le quattro directory /usr/bin:/bin:/usr/sbin:/sbin (leggetele ad alta voce e notate l’assonanza). Cancellare per errore una di queste directory dal PATH significa non poter più usare il Mac, o perlomeno dover usare degli strumenti non alla portata di tutti per rimettere a posto le cose.

Siete avvertiti!!!

Modificare il PATH

Per aggiungere (o rimuovere) delle directory al PATH di default del nostro Mac dobbiamo modificare con un editor di testo (non con un wordprocessor!) il file .bashrc situato nella nostra HOME. Questo introduce una piccola complicazione, perché il file ~/.bashrc è un file nascosto, non accessibile direttamente dal Finder.

Se usiamo emacs o vi possiamo aprire .bashrc direttamente dal Terminale. Ci basta spostarci nella HOME

$ cd ~

ed eseguire

$ emacs .bashrc

oppure

$ vi .bashrc

Se questi editor ci sembrano troppo difficili da usare (e lo sono!), possiamo usare nano che, come emacs e vi, si trova installato di default su ogni Mac

$ nano .bashrc

Anche se nano è un editor piuttosto limitato rispetto ai due mostri sacri, è molto comodo per modificare velocemente i file di sistema senza dover affrontare una lunga fase di apprendimento.

Se invece preferiamo usare un editor grafico come BBEdit, TextMate, Atom o simili, la procedura esatta per aprire un file nascosto dipende dall’editor scelto.

Alcuni editor permettono di installare un comando di Terminale con cui lanciare l’editor dalla linea di comando: mate per TextMate, atom e bbedit per… lo sapete già. Anche con questi editor, quindi, possiamo aprire .bashrc dal Terminale con uno dei comandi seguenti

$ mate .bashrc 
$ atom .bashrc
$ bbedit .bashrc

Con BBEdit e TextMate, la finestra di apertura file dispone di un tasto Opzioni con il quale si può decidere di mostrare (e quindi di aprire) anche i file nascosti


Ma il metodo più generale per modificare un file nascosto con un editor grafico è quello di usare il comando open dal Terminale

$ cd ~
$ open -a "TextMate" .bashrc

dove l’opzione -a permette di specificare l’applicazione con cui aprire il file indicato.

Qualunque sia il metodo utilizzato, alla fine ci ritroveremo con il file .bashrc pronto per essere modificato. Tutto quello che dobbiamo fare è aggiungere questa linea alla fine di .bashrc

export PATH=$PATH:~/Development

che istruisce la shell di andare a cercare i comandi da eseguire nel Terminale anche nella directory ~/Development, dove abbiamo deciso di salvare tutti gli script che sviluppiamo.

Una volta fatta questa semplice modifica, salviamo il file .bashrc e usciamo dall’editor. Chiudiamo e riapriamo il Terminale per costringere la shell a rileggere il file .bashrc (oppure eseguiamo il comando $ source ~/.bashrc senza chiudere il Terminale) e proviamo di nuovo ad eseguire nomescript, ma questa volta senza premettere il percorso alla directory dove si trova

$ nomescript

Questa volta lo script funzionerà senza bisogno di aiutini, proprio come se fosse un normale comando di sistema. Per verificare che tutto funzioni come descritto possiamo provare ad eseguire uno degli script della terza o della quinta puntata.

Ma non è ancora finita…

Bisogna ammetterlo, aggiungere al $PATH una directory qualunque come ~/Development può andar bene per fare delle prove veloci, ma non è per niente elegante. Sarebbe molto meglio adeguarsi alle convenzioni di Unix, secondo le quali i programmi eseguibili devono trovarsi in una directory denominata bin.

Niente di più facile, possiamo creare facilmente una directory bin nella nostra HOME

$ cd
$ mkdir bin

e decidere di tenere gli script in fase di sviluppo nella directory ~/Development, per poi spostarli (o meglio copiarli) in ~/bin quando sono pronti per essere usati. Naturalmente dovremo modificare di conseguenza il file .bashrc, aggiungendo alla fine del file

export PATH=$PATH:~/bin

al posto di export PATH=$PATH:~/Development visto sopra.

Non ci piace vedere con il Finder la directory bin nella HOME? Possiamo nasconderla con facilità, basta solo eseguire dal solito Terminale il comando

$ chflags hidden ~/bin

(il comando duale $ chflags nohidden ~/bin rende di nuovo visibile la directory).

Conclusioni

Per i più pigri che non vogliono andare a rileggere le puntate precedenti per provare le novità descritte nell’articolo, ecco un semplice script in bash che mostra la data e l’ora corrente nel formato standard Unix e in una forma molto più dettagliata (e per una volta anche nella nostra lingua)

#!/bin/bash

year=`date +%Y`
month=`date +%B`
day=`date +%d`
hour=`date +%H`
minute=`date +%M`
second=`date +%S`
dayofyear=`date +%j`
weekday=`date +%A`

echo `date`
echo -n "Oggi è $weekday $day $month $year, "
echo -n "il $dayofyear-esimo giorno dell'anno, "
echo "e sono le ore $hour:$minute:$second"

Copiamo lo script nell’editor preferito, salviamolo in ~/bin (o in ~/Development) con il nome data_estesa, rendiamolo eseguibile con chmod e proviamo che funzioni come previsto

$ data_estesa
Fri Apr 12 17:28:50 CEST 2019
Oggi è Venerdì 12 Aprile 2019, il 102-esimo giorno dell'anno, e sono le ore 17:28:50

E per oggi è davvero tutto.

Articoli precedenti

Per leggere gli articoli precedenti della serie basta cliccare sui link qui sotto.


  1. Sul Mac uno script in bash richiede il percorso /bin/bash, uno in awk puro /usr/bin/awk, mentre uno nella ormai veneranda versione 2.7 di python installata di default in macOS richiede /usr/bin/python (ma ci vuol poco ad installare python3 con Homebrew o Conda). 
  2. Ma ci sono anche zsh, ksh, tcsh, fish, solo per menzionare le shell più note. 
  3. È esattamente quello che fa Homebrew, uno strumento utilissimo (di cui ho scritto parecchio su questo blog) che utilizza /usr/local/bin per installare un gran numero di strumenti software provenienti dal mondo Linux e non disponibili su macOS, oppure per aggiornare a versioni più recenti quelli, normalmente piuttosto datati, forniti da Apple insieme al sistema operativo. 
Annunci
Tagged with: , , , , , ,
Pubblicato su programmazione
One comment on “Script per tutti i giorni: lo script è il comando
  1. Frix ha detto:

    Grazie, chiaro e puntuale come sempre.

    Per ringrazio e basta!
    Pizza (o braciola), birra (o rosato del Salento) e caffé al primo incontro!!!😂

    Mi piace

Rispondi

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 )

Google photo

Stai commentando usando il tuo account Google. 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 )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

Informativa
Questo sito utilizza cookie di terze parti per inviarti pubblicità e servizi in linea con le tue preferenze. Se vuoi saperne di più o negare il consenso a tutti o ad alcuni cookie, clicca qui. Scorrendo questa pagina, cliccando su un link o su qualunque altro elemento o proseguendo la navigazione in altra maniera, acconsenti all'uso dei cookie.
Follow Melabit on WordPress.com
Categorie
%d blogger hanno fatto clic su Mi Piace per questo: