Bash Scripting
Per Bash si intende il terminale dei comandi Bash, quello schermo nero col cursore lampeggiante da cui e' possibile fare tutto con linux:
La sigla BASH significa Bourne Again Shell, cioe' Shell rinata, perche' e' successiva a molte altre shell.
Per scripting Bash si intende una serie di comandi, sia interni a bash che esterni, con cui e' possibile ottenere programmi che ci semplificano notevolmente l'esistenza.
Il primo script
Per scrivere uno script basta un qualunque editor di testo (attenzione: non elaboratore di testi come OpenOffice o Word) come vim o emacs, oppure kate.
Ma facciamo un esempio: innanzitutto dobbiamo creare un file per esempio primoscript, una volta creato lo apriremo con il nostro editor preferito (il mio e' Vim).
Fatto cio' cominciamo a digitare:
#! /bin/bash # questo e' un commento qualunque # ho voglia di fare un programma che copia i file ls echo "Quale file vuoi copiare?" read origine echo "Dove lo vuoi copiare?" read destinazione cp $origine $destinazione
mi raccomando in questo caso va scritto tutto # compreso.
La prima riga dice al sistema operativo che e' uno script da avviare con /bin/bash. Le altre riche che cominciano per # sono deicommenti di chi scrive il programma, e percio' sono ignorati dal computer, il resto sono comandi Linux.
Allora il file in questione dovrebbe darmi la lista di tutti i file nella directory corrente chiedermi l'input di un file da copiare e il nome del file da mettergli, MA NON LO FARA' MAI.
Attenzione: Dovete rendere il file eseguibile altrimenti non fara' nulla, nel terminale dovete scrivere:
$ chmod ugo+x primosciprt
(u=user g=goup o=other) cosi' chiunque potra' usare lo script.
A questo punto sempre nel terminale spostandovi nella cartella dove e' lo script:
$ ./primoscript
e tutto partira' come descritto (./ serve per fargli capire dove deve guardare (cioe' la directory in questione), ma potrebbe essere superfluo).
Variabili
Le variabili sono contenitori di dati, una volta definita una variabile, essa e' identificata antenponendo il simbolo di dollaro (var non e' una variabile, $var lo e')'. Le variabili all'interno degli script possono avere un qualunque nome, come $pippo o $Caterina, ma attenzione alle maiuscole e minuscole, $Pippo e' una variabile diversa da $pippo.
Oltre a questo tipo di variabili ne esistono altre, ma vediamo prima un esempio:
#!/bin/bash # Script per creare copie di backup cp $1 $1.backup
La variabili che abbiamo usato nel programma precedente (cp $1 $1.backup) serve per indicare il file che dobbiamo copiare ($1) e il nome del nuovo file ($1.backup), le variabili composte solo da un numero ($1, $2, ..., $30 e cosi' via...) sono gli argomenti passati agli script.
Variabili speciali
Esistono delle variabili riservate che permettono di ottenere brevemente dei dati, esse sono:
- $# : Contiene il numero degli argomenti passati allo script.
- $@ : Contiene tutti gli argomenti separati da uno spazio.
- $0 : Contiene il nome dello script, utile per messaggi di debug.
- $$ : Contiene l'ID dello script, utile se volete ucciderlo con kill.
- $? : Contiene il codice di uscita dell'ultimo programma eseguito dalla shell (di solito se e' diverso da zero, c'e' stato un errore).
Valutare le variabili
Quando bisogna valutare un'espressione, tipo A < B, e' facile sbagliarsi, se non si specifica bene uno script puo' pensare che una variabile anziche' contenere un valore, per esempio 23, contenga un testo, e valutando caratteri e non numeri. Per specificare i valori numerici del contesto di una valutazione, bisogna virgolettarle, esempio:
if [ "$A" -le "$B" ] then echo $A e' minore di $B else echo $A e' maggiore di $B fi
Inoltre per valutarle non si usano i simboli >, >, =, <=, >=, !=.Ma si usano le seguenti notazioni:
- -eq : Uguale (equal)
- -lt : Minore (less than)
- -gt : Maggiore (greater than]
- -le : Minore o uguale (less or equal)
- -ge : Maggiore o uguale (greater or equal)
- -ne : Diverso (not equal)
I simboli = (uguale) e =! (diverso), vanno bene solo per il confronto tra file o testi.
Inoltre si possono verificare altre cose su i file:
- -e : esistenza
- -f : file normale
- -d : se e' una directory
- -h : collegamento simbolico
- -b : periferica a blocchi
- -c : periferica a caratteri
- -p : named pipe
- -S : socket
- -r : leggibile
- -w : scrivibile
- -x : eseguibile
- -u : impostato il setuid
- -g : impostato il setgid
- -k : impostato lo ''Sticky byte"
Assegnare valori alle variabili
A una variabile puo' essere assegnato un valore sia numerico (1, 2.5, 110, 5.025) che il valore di una stringa (ciao, cavallo, il mondo e' bello); oppure il valore dato da un comando, per esempio il numero della data di oggi (date '+%d'). Vediamo come fare:
primavariabile=19 # abbiamo assegnato il valore 19 secondavariabile=Giovanni # abbiamo assegnato il valore Giovanni terzavariabile=`date '+%d' ` # abbiamo assegnato un comando
Come si vede per assegnare un comando basta mettere il comando tra apici inversi; per scrivere un apice inverso bisogna battere [AltGr+'], cioe' l'Alt di destra insieme all'apice normale.
Non vanno messi spazi, ne' davanti, ne' dietro all'uguale; altrimenti e' tutta un'altra cosa.
Nota: Se si vuole mettere le virgolette, o altri caratteri che possono essere confusi, basta mettere il carattere di escape \ davanti al simbolo.
Aggiungere (append)
E' possibile aggiungere usando +=, esempio:
A="ciao" A+=" mondo" echo $A # A adesso e' "ciao mondo"
Caratteri speciali
Il carattere *, e' interpretato come tutte le directory e tutti i file presenti nella directory attuale. Cio' significa che per vedere tutti i file e le cartelle della directory attuale si puo' anche lanciare il seguente comando (o script):
$ echo * Cartella1 Cartella2 file1 file2
Se invece volessimo far apparire l'asterisco sul monitor, basterebbe usare gli apici singoli ('), che non fanno interpretare alcun che' oltre il significato letterale, quindi il seguento comando funziona cosi':
$ echo '*' *
Ma se a noi servono sia l'asterico, o l'apostrofo e l'interprezazione delle variabili? Allora si usano i doppi apici, tali permettono solo l'interpretazione delle varibili, e l'apostrofo deve essere preceduto dalla backstick, esempio:
$ $frase="mi sembra ovvio" ; echo "Questo e\' un asterico: * , $frase" Questo e' un asterico: * , mi sembra ovvio
Ottenere l'input dall'utente
Per ottenere l'input dall'utente basta dare il comando read, la sintassi e' la seguente:
read test
esempio:
#! /bin/bash read frase echo $frase
Scegliere (IF)
Molte volte un programma deve prendere delle decisioni, un modo per rendere in grado il computer di scegliere e' di usare l'istruzione IF. Se si riesce a porre il quesito in termini di vero o falso, il computer cambiera' comportamento.
Prendiamo ad esempio che il computer legga un numero e se e' pari ci avverta che e' pari altrimenti ci avvertira' che e' dispari. Un numero pari ha come resto zero se viene diviso per 2, quindi il computer dovra' solo verificare che il resto e' zero; mi raccomando di mettere sempre almeno uno spazio prima e dopo le parentesi quadre, altrimenti unira' le parentesi alle variabili cercando comandi assurdi:
#! /bin/bash echo Inserisci un numero read numero resto=`expr $numero % 2` if [ "$resto" -eq 0 ] then echo "Il numero $numero e' pari" else echo "Il numero $numero e' dispari" fi echo \n Programma terminato
Vediamo qual e' la sintassi corretta del comando "if":
if [lista] then [lista] else [lista] fi
In pratica se la lista d'istruzioni dopo if da' come risultato il valore vero (le parentesi quadre significano "valuta l'espressione") allora vengono eseguite le istruzioni che seguono il then, altrimenti vengono fatte quelle che seguono else (che puo' pure non essere messo). Una serie di if in seguenza puo' essere sostituita dalla seguente scrittura (dove si usa elif):
if [lista] then [lista] elif [lista] then [lista] elif [lista] then [lista] fi
I test sono fatti fra file se si usano i simboli (=, < , > , ecc.), mentre sono fatti fra numeri se si usano le abbreviazioni viste prima.
Sistemi piu' concisi
Per chi vuole rendere il proprio stile di programmazione strano e misterioso, si possono utilizzare le seguenti abbreviazioni per scrivere tutto in una riga:
- [ ] =condizione
- && =then
- || = else
quindi il seguente codice e' corretto (fate attenzione a mettere gli spazio vicino ai simboli speciali):
[ $numero -gt 10 ] && echo "il numero รจ maggiore di 10" || echo "il numero non e' maggiore di 10"
Scegliere fra molti (CASE)
Un altro sistema, invece di utilizzare tanti IF e' quello di usare CASE:
case $temp in 1) echo "temp vale 1" ;; 2) echo "temp vale 2" ;; *) echo "Temp non vale ne' 1 ne' 2" ;; esac
Potete mettere qualsiasi numero di condizioni.
Fare finche' (WHILE)
Il comando while permette ripetere una serie di comandi finche' non si verifichera' una condizione. Esempio:
#! /bin/bash echo Scriviamo i numeri da 1 a 30 n=1 while [ "$n" -le 30 ] do echo $n n=`expr $n + 1` done echo Finito
In questo modo saranno scritti tutti i numeri da 1 a 30, non dimenticatevi di scrivere done per chiudere la serie di comandi da ripetere.
Fare menu' testuali
Se si vuole fare un menu' basta usare il comando "select", questo comando e' un risparmio di tempo incredibile! Vediamo come:
#! /bin/bash OPTIONS="Hello Quit" select opt in $OPTIONS; do if [ "$opt" = "Quit" ]; then echo done exit elif [ "$opt" = "Hello" ]; then echo Hello World else clear echo bad option fi done
Una volta eseguito otterrete un menu' numerato che vi permette di scegliere l'opzione che preferite. Se non si mette il comando exit, dopo avere eseguito l'operazione richiesta, si si ritorna sempre al menu numerato.
Ciclo FOR (fare per n volte)
Vediamo un esempio un cui stampiamo i nomi dei file che finiscono in MP4.
for temp in *.mp4 do echo $temp done
possiamo anche fare una ciclo tra due numeri, ad esempio da 1 a 10:
for i {1..10} do echo $i done
oppure la stessa cosa si puo' scrivere cosi':
for ((i = 0 ; i <= 10 ; i++)) do echo $i done
Input e output
Ecco una serie di articoli riguardanti l'input e l'output dei comandi:
Usare nomi di file unici
Se ci serve che nessun altro usi i nostri file mentre ci lavoriamo, possiamo usare un programma che crea nomi unici: mktemp. Uso:
$ nome=`mktemp miofile_XXXXXX` ; echo $nome miofile_b18290 $ nome=`mktemp miofile_XXXX` ; echo $nome miofile_8293
Come vedete sostituisce alla lettera X, caratteri che rendano unico il file (consiglio per estrema sicurezza almeno sei X).
Matematica
Per valutare espressioni matematiche c'e' expr (occhio agli spazi):
$ expr 1 + 2 3
ATTENZIONE: Questo programma pero' risente dei caratteri jolly e delle espressioni regolari, per esempio pensa che * sia tutti i file presenti nella directory corrente, quindi l'espressione:
$ expr 5 * 5 expr: syntax error
da' errore, ma se si usa il carattere \ davanti, si fa' capire ad expr che si intende solo il simbolo del prodotto e non altre cose:
$expr 5 \* 5 25
Nomi files particolari
Alcuni nomi dei file potrebbero creare dei problemi con gli script, perche' se il nome inizia on il meno (-) o col punto (.) bash li puo' interpretare o come opzioni o come altre cose che portano ad errore. Per ovviare a cio' basta usare il doppio meno dopo le opzioni dei comandi (--). Ad esempio questo script prende le foto di una cartella, crea una cartella per ogni foto e ce le mette dentro e le foto possono avere qualsiasi carattere iniziale:
for temp in *.jpg do tempdir=`basename -s ".jpg" -- $temp` mkdir -- $tempdir mv -- $temp $tempdir done