Guida Linux: la programmazione della shellNei sistemi Linux e' possibile programmare la shell, cioe' creare dei programmi per eseguire automaticamente delle operazioni che altrimenti si dovrebbero eseguire manualmente. Ad esempio e' possibile creare un programma per effettuare periodicamente il salvataggio dei dati su un supporto esterno (nastro, floppy, CD-Rom etc), oppure si potrebbe scrivere un programma che controlla lo spazio occupato sul disco e produce delle statistiche. Non ci sono limiti alle possibili applicazioni che possono essere gestite automaticamente da un programma: l'unico limite e' la fantasia del programmatore. Bene, tali programmi vengono definiti script della shell (per chi conosce il SO MSDOS: possono essere paragonati ai file .bat). Per scrivere uno script della shell si puo' utilizzare un qualsiasi editor di testo come VI, EMACS, JED e via dicendo. Una volta scritto lo script, per eseguirlo occorre renderlo eseguibile impostando i permessi di esecuzione (utilizzando il comando chmod) oppure usare il comando sh od il comando '.'. Entrambi questi comandi eseguono lo script che viene loro passato come argomento. Ad esempio, supponendo di aver scritto uno script chiamato pippo, impostandone i permessi di esecuzione con il comando chmod, tale file diventera' simile ad un comune comando Linux: digitandolo e premendo INVIO verra' eseguito:
chmod u+x pippo Uno script della shell puo' contenere dei comuni comandi Linux, delle righe di commento ed una prima riga di commento un po' speciale. Quando un file di script viene eseguito la shell legge tale file riga per riga ed esegue tutte le istruzioni che incontra: si tratta percio' di un programma intrpretato. Tutte le righe che iniziano con il carattere cancelletto '#' vengono trattate come commento e sono percio' ignorate dalla shell. Le righe di commento sono particolarmente utili nella scrittura di script complessi per descrivere lo scopo del codice che si sta scrivendo. La primissima riga di commento pero' ha una funzione ben precisa: indicare il tipo di shell che potra' eseguire lo script ed eventualmente la locazione del disco o piu' esattamente il path per richiamare tale shell. Nel caso questa prima riga di commento venga omessa verra' chiamata la shell di default, cioe' la shell BASH. Infatti se il primo carattere e' uno spazio si suppone che tale script e' eseguibile dalla shell bash, se tale carattere e' un cancelletto si suppone che la shell da usare sia la TCSH. Inoltre e' possibile scrivere il carattere ! dopo il carattere # per specificare una shell diversa, ma in questo caso occorre anche indicare il path per reperire tale shell: #!/bin/sh. Quest'ultima notazione e' indispensabile se si utilizza una shell e si crea uno script per un'altra shell. Ad esempio se si utilizza la shell TCSH e si scrive uno script per la shell BASH e' indispensabile iniziare tale script con la stringa: #!/bin/sh, dove /bin/sh e' il path di default della shell BASH (ovviamente se in un particolare sistema la shell BASH si trova in una locazione diversa il relativo path da specificare dovra' essere diverso). Il comando echo visualizza in output una stringa. Vediamo un classico esempio di programma che utilizza il comando echo:
mioscript e' il nome dello script e contiene al suo interno le seguenti istruzioni: Uno script generalmente accetta dei dati in input e genera dei dati in output: il comando read permette di leggere l'input ed il comando echo permette di scrivere in output. Ad esempio:
lo script mioscript contiene: nello script appena visto l'istruzione read legge lo standard input e lo mette nella variabile $qualcosa, successivamente il comando echo visualizza il contenuto della variabile. Poiche' la stringa passata al comando echo e' inserita tra una coppia di doppi apici, eventuali caratteri speciali all'interno della variabile qualcosa non vengono valutati. Nel caso occorresse valutare eventuali caratteri speciali occorrera' eliminare i doppi apici. Ad esempio si potrebbe creare un comando che prendesse in considerazione anche eventuali caratteri speciali digitati dall'utente per effettuare alcune elaborazioni. Osserviamo il seguente script:
lo script elenco contiene: l'utente digita il nome dello script (elenco) seguito dall'argomento *.txt. L'asterisco e' un carattere speciale che in questo caso viene preso in input dallo script e valutato in quanto la variabile $nomi non e' posta tra doppi apici. Percio' il comando ls accetta in input il contenuto della variabile passata allo script elenco e cioe' '*.txt'. Ad ogni modo uno script puo' leggere dei dati anche da se stesso:
lo script inviamail contiene: la stringa <<fine significa: prendi in input tutto cio' che trovi da questo punto fino alla parola 'fine'. Se non si specifica un punto di terminazione occorrera' inserire il carattere di fine file CTRL-D. Ovviamente dopo i caratteri << e' possibile scrivere qualsiasi cosa come ad esempio <<stop, <<end e via dicendo. Come qualsiasi comando Linux, anche gli script accettano degli argomenti in input. Per far riferimento ad un argomento e' possibile usare il simbolo $ seguito dal numero dell'argomento: $0 e' il nome dello script, $1 e' il primo argomento, $2 e' il secondo, $3 il terzo e cosi' via. $# rappresenta il numero degli argomenti passati in input e $* rappresenta tutti gli argomenti. Un esempio chiarira' il concetto:
mio script arg1 arg2 arg3 Veniamo ora alla prima istruzione utilizzabile all'interno di uno script: l'istruzione let. Let confronta due valori o permette di eseguire delle operazioni aritmetiche. Attenzione: let confronta due valori e non due espressioni. Esempi:
let 3*5 come si puo' vedere se gli argomenti del comando let contengono spazi, occorre quotarli usando i doppi apici. Il comando while appena visto e' una struttura di controllo che vedremo successivamente insieme alle altre strutture (if, for, for-in e case) in quanto occorre prima introdurre la struttura di controllo test. Il comando test permette di confrontare due valori. E' possibile confrontare due valori usando il comando test o inserendo l'espressione di confronto all'interno di una coppia di parentesi quadre. Per verificare l'uguaglianza tra due valori occorre usare il simbolo '=' oppure l'opzione -eq del comando test. Viceversa, per verificare la disuguaglianza tra due valori occore usare il simbolo "!=":
num=2 la verifica dei valori usando il comando test o le parentesi quadre e' usata all'interno di strutture di controllo come while, if, for, for-in e case- La sintassi della struttura di controllo if e' la seguente:
if comando-linux Ogni comando linux quando termina restituisce un codice di errore che puo' essere 0 se il comando non ha successo o 1 se il comando e' andato a buon fine. Tale codice di errore viene verificato dalla struttura di confronto if: se e' 1 vengono eseguiti i comandi successivi alla parola then, in caso contrario vengono eseguiti i comandi successivi alla parola else. Vediamo il funzionamento della struttura di controllo if con lo script 'argomenti' che accetta degli argomenti in input e verifica che il numero di questi sia corretto: se viene passato piu' di un argomento visualizza un messaggio di errore:
if [$# -ne 1] e' possibile 'nidificare' le if, ossia effettuare piu' controlli usando la sintassi 'elif' (elif sta per 'else if'). In altre parole se non si verifica la condizione testata vengono eseguiti i comandi successivi alla parola else ma a questo punto e' possibile eseguire un altro controllo utilizzando un altro comando if dopo la parola elif:
if [conddizione1] come abbiamo visto il costrutto if permette di verificare l'esito di un comando Linux: e' possibile pero' verificare l'esito di due o piu' comandi Linux usando gli operandori logici && e ||. L'operatore logico && corrisponde all' and logico mentre l'operatore || corrisponde all' or logico. Cio' significa che se si vuole verificare che due o piu' comandi siano andati a buon fine contemporaneamente occorre usare l'operatore &&, mentre se si vuole verificare che almeno uno dei comandi sia andato a buon fine occorre usare l'operatore ||: comando1 && comando2 oppure comando1 || comando2. Nel primo caso viene eseguito tutto cio' che si trova dopo la parola then solo se entrambi i comandi hanno esito positivo mentre nel secondo caso e' sufficiente che almeno uno dei due comandi abbia esito positivo. Quando occorre verificare piu' condizioni, e' conveniente usare la struttura di controllo case. Vediamo il costrutto case con un esempio di script che visualizza un menu dove e' possibile scegliere tra le varie opzioni per visualizzare i file:
echo "scegli una opzione tra le seguenti: cosi' come per il costrutto if anche il costrutto case deve terminare con una parola particolare: esac. Come si puo' osservare fi e' if letto in senso contrario ed esac e' case letto in senso contrario. ;o) Vediamo infine i costrutti while, for e for-in. Il costrutto while permette di eseguire un ciclo di comandi mentre e' verificata una condizione. Quando la condizione non e' piu' verificata il ciclo si interrompe e lo script prosegue dall' istruzione successiva al blocco del while. La sintassi dell'istruzione while e' la seguente:
while comando-linux Il costrutto for permette di costruire cicli di comandi. Verranno eseguiti tanti cicli quanti sono gli argomenti passati allo script. Ogni argomento viene spostato all'interno di una variabile che verra' verificata dal ciclo di for. Vediamo un esempio con lo script 'copiafile' che permette di salvare i file specificati all'interno di una data directory:
for miofile il costrutto for-in e' molto simile al costrutto for con la sola differenza che l'elenco dei valori non viene preso dall'elenco degli argomenti passati allo script ma dall'elenco fornito direttamente all'interno del costrutto for-in:
for variabile in pippo pluto topolino Infine il comando exit permette di uscire immediatamente dallo script fornendo un codice di errore che puo' essere 0 o qualsiasi altro numero. Non appena viene incontrato il comando exit, lo script termina ed il controllo torna alla shell.
Copyright (c) 2002 M. Silvestri |