Lo scripting language è il linguaggio di programmazione interpretato dalla shell. Esso si compone di comandi interni (built-in), propri di Bash, file eseguibili ed operatori aritmetico-logici.
È possibile pertanto realizzare degli script, ovvero files di testo che contengono istruzioni comprensibili dalla shell e da questa interpretate ed eseguite. Tali istruzioni possono essere composte dai comandi interni della shell e dai comandi del sistema (nomi di file eseguibili) con la sintassi accettata dalla riga di comando. Scrivere uno script di shell è come scrivere una sequenza di comandi da poter far eseguire in blocco alla shell indicando semplicemente il nome del file che li contiene (lo script)12.
Ad esempio, se si vuol fare eseguire in sequenza i comandi
$ echo Sto creando il file 'pippo'
$ ls > pippo
si può creare un file prova (ad esempio con il comando vi prova) ed inserire al suo
interno le righe seguenti
echo Sto creando il file 'pippo'
ls > pippo
poi fare in modo che tale file sia eseguibile, con il comando
$ chmod u+x prova
A questo punto sarà sufficiente digitare il comando
$ ./prova
per far eseguire i comandi in esso contenuti.
In realtà Bash mette a disposizione un potente scripting language, con la valutazione di espressioni condizionali, cicli, inclusioni di file, che permette di automatizzare in maniera piuttosto semplice qualunque operazione di sistema.
Il lancio in esecuzione di un comando può richiedere degli argomenti sulla riga di comando. Questi vengono passati come parametri al processo che viene posto in esecuzione dalla shell che si preoccupa di “tokenizzarli” (separarli l’uno dall’altro, riconoscendo come simbolo separatore il carattere spazio ‘ ’).
Allo stesso modo, anche gli script Bash possono ricevere degli argomenti dalla riga di comando. Gli argomenti passati agli script sono memorizzati nei parametri $0, $1, $2, ... dello script stesso.
Come trattato nel cap. 7, quando un processo termina, esso ritorna un valore di uscita, detto exit status, cioè un valore numerico di un byte. L’exit status dell’ultimo processo eseguito viene memorizzato nel parametro $?.
Quando viene impartito un comando, rappresentato da un file eseguibile, la shell crea un nuovo processo per la sua esecuzione secondo quanto di seguito riportato:
#!/bin/bash
in modo tale che, se tale file viene specificato come comando (ed il file ha il
permesso di esecuzione per l’utente considerato), la shell lanci in esecuzione
il file /bin/bash, ovvero l’interprete Bash, al quale fare interpretare il file
stesso.
Si supponga infatti di avere il file di testo ~/pippo con il seguente contenuto:
#!/bin/bash
echo Ciao a tutti !
e di avere almeno i diritti di lettura e di esecuzione su quel file. Lanciando il
comando
$ ~/pippo
la shell si accorge che il file pippo presente nella home directory dell’utente corrente ‘~’ è
non è un file binario, quindi lo tratterà come se fosse uno script, estraendo dalla prima
riga il nome dell’interprete da lanciare per eseguire tale script, ovvero /bin/bash, che
provvederà a lanciare in esecuzione come processo figlio, passandogli come input lo
script.
#!/usr/bin/perl
print "Ciao a tutti !"
La sintassi del linguaggio di scripting di Bash è piuttosto articolata, e di seguito saranno riportate alcune caratteristiche essenziali per la comprensione e realizzazione di semplici script. Per una descrizione più dettagliata della programmazione con Bash v. [0].
I comandi vengono scritti in sequenza su righe diverse. Alcuni caratteri assumono un significato particolare, di seguito illustrato:
echo salve # mondo
# mondo è considerato un commento;
echo salve; echo mondo
viene considerata come
echo salve
echo mondo
case "$variable" in
abc) echo "$variable = abc" ;;
xyz) echo "$variable = xyz" ;;
esac
let "b = ((a = 1, 21 / 7))"
imposta a col valore 1 e b col valore 3 (= 21/7);
echo salve \# mondo
in questo caso il carattere # viene considerato come tale, non assume il significato di
inizio di un commento.
MyArray=(value1 value2 value3)
grep Linux myfile*.{txt,htm*}
trova tutte le istanze della parola “Linux” nei file che iniziano per myfile ed
hanno estensione txt o che inizia per htm;
echo ${MyArray[1]};
visualizza il valore contento nel secondo elemento (1) del vettore MyArray;
[ -n "$var" ]
ritorna vero (0) se la variabile var non è stata inizializzata;
[[$var1 > $var2 ]]
ritorna vero se il contenuto della variabile var1 è maggiore di quello della variabile
var2.
echo "ciao" >~/myfile
redirige l’output del comando echo "ciao" nel file ~/myfile, sovrascrivendolo se
il file esiste già. Il comando
echo "ciao" >&2
redirige l’output del comando echo "ciao" nel file descriptor 2, ovvero l’error
associato al processo.
echo "ciao" &>~/myfile
redirige l’output e l’error del comando echo "ciao" nel file ~/myfile, sovrascrivendolo se
il file esiste già.
echo "ciao" >>~/myfile
redirige l’output del comando echo "ciao" nel file ~/myfile, aggiungendolo a quanto
già contenuto nel file. Se il file non esiste viene creato.
tail <~/myfile
redirige l’input del comando tail sul file ~/myfile. In questo modo tail
gestisce il contenuto del file ~/myfile come se fosse digitato dalla tastiera
(standard input);
$ file
Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...
mentre
$ file -
abc
standard input: ASCII text