Pagina 1 di 1

Script Bash

Inviato: venerdì 2 marzo 2012, 23:48
da conoscenza
Attualmente l'argomento è bloccato per motivi di espansione ed aggiornamenti.
Alla fine di questo lavoro verranno pubblicati degli esempi reali di script bash, magari anche a voi utili.

0) Premessa

1) Introduzione

2) Caratteri speciali

3) Assegnamento di una variabile

4) Quoting & Escape

5) Costrutti condizionali if/then e if/then/elif

6) Cicli for, while e until

7) Break e continue

8) Sostituizione di un comando

Re: Script Bash

Inviato: venerdì 2 marzo 2012, 23:49
da conoscenza
Premessa

Prima o poi tutti gli utenti Linux, dopo aver assaporato l'utilizzo e la praticità della shell, passano alla programmazione degli scipt bash.
Perchè usare gli script bash? Il motivo è semplice. Gli script più semplici contengono solamente delle righe di comando che vengono interpretate dalla shell, ma fin qui non ci sono grossi benefici. Gli script bash possono contenere verifiche, cicli, espressioni regolari e quant'altro per rendere lo script "dinamico". Infatti sarebbe di difficile, se non impossibile, implementare un "case" o un "for" all'interno della shell. Inoltre gli amministratori possono utilizzare tale strumento per eseguire automaticamente compiti di routine, in avvio o in chiusura macchina, o ad ore e giorni pianificati.
Sull'argomento esistono manuali da oltre 700-800 pagine, qui se ne tratteranno i punti fondamentali per iniziare a scrivere i primi script bash, per non rendere noioso il lavoro tentando invece di giungere subito al nocciolo dell'argomento.
Nulla vieta di aprire nuovi thread nella sezione a Linux dedicata per aiuti vari a problemi legati allo script bash.
Il lavoro verrà concluso con esempi di script bash.
Non mi resta che augurarvi buona lettura e buona programmazione.

Re: Script Bash

Inviato: venerdì 2 marzo 2012, 23:50
da conoscenza
Introduzione

Uno script bash inizia sempre, prima di ogni commento, con la sintassi:
#! /bin/bash
Questa sintassi permetterà di riconoscere, non appena salvate, il vostro file di testo come un file di script e informano il sistema che il file contiene una serie di comandi che devono essere passati all'interprete indicato.
Per commentare si usa il carattere "#", che posto in una qualsiasi parte del testo rende, ciò che sta dopo fino alla fine del rigo, non interpretabile per la shell.
Ovviamente dopo aver scritto lo script bisogna anche renderlo eseguibile.
Basterebbe un:

Codice: Seleziona tutto

chmod 555 nomescript
per renderlo eseguibile da tutti gli utenti, ma spesso non è quel che si vuole.
Rimando qui per ulteriori informazioni sui permessi di esecuzione.

Infine, ricordo, che è possibile lanciare uno script bash utilizzando il comando "sh" con la sintassi generica:

Codice: Seleziona tutto

sh <path_script>/<nome_script>

Re: Script Bash

Inviato: venerdì 2 marzo 2012, 23:51
da conoscenza
Caratteri speciali

#: come abbiamo già detto il carattere # serve a commentare quel che segue fino alla fine del rigo.

;: separa due o più comandi sulla stessa riga.

": quoting parziale (anche detto quoting debole).

': quoting totale (anche detto quoting forte).

\: quoting per singoli caratteri.

!: inverte o nega il senso di una verifica o di un exit status.

*: serve da carattere "jolly" per l'espansione dei nomi dei file.

$: sostituisce una variabile con il suo contenuto/valore.

${}: sostituisce il paramentro.

$(): sostituisce il comando.
(Ad esempio nella shell di bash si può usare:

Codice: Seleziona tutto

cd /usr/src/$(uname -r)/
per entrare nella directory del kernel attualmente in uso.

$?: variabili di exit status. Contiene l'exit status di un comando, funzione o dello stesso script.

[]: espressio di verifica.
NB: a questo [] si preferisce il costrutto [[...]].

{...}: espansione multipla
(AD esempio {1..10} darà {1 2 3 4 5 6 7 8 9 10})
Le partensi graffe possono anche raccogliere un insieme di codice.

|: passa l'output del comando che la precede come input del comando che la segue. Questo metodo è usato per concatenare comandi.

||: operatore OR

&&: operatore AND

=: operatore di assegnamento

Rimando qui per ulteriori caratteri speciali.

Re: Script Bash

Inviato: venerdì 2 marzo 2012, 23:55
da conoscenza
Assegnamento di una variabile

Per assegnare una variabile si usa l'operatore di assegnamento con il carattere "=".
Si noti che nell'uso di =, non serve né lo spazio prima e nemmeno dopo l'operatore di assegnamento.
Diverso è invece nel caso delle verifiche, dove " = " e " -eq " necessitano del carattere spazio, sia prima che dopo.
Esempio esplicito:

Codice: Seleziona tutto

a=20
quindi dando:

Codice: Seleziona tutto

echo $a
ci verrà restituito il valore 20.
Quindi possiamo utilizzare l'assegnazione anche con una forma di sostituzione di comando, ad esempio assegnando in maniera del tutto generale l'architettura utilizzata alla variabile arch:

Codice: Seleziona tutto

arch=$(uname -m)
NB: le variabili negli script bash non sono tipizzate, questo significa che non differenzia le variabili per "tipo".
Questo rende gli script molto flessibili, ma d'altra parte, se chi li scrive non mantiena traccia del tipo di variabile, si finisce facilmente per commettere errori subdoli.

Re: Script Bash

Inviato: venerdì 2 marzo 2012, 23:56
da conoscenza
Quoting & Escape

Fare il quoting non è nient'altro che mettere una stringa tra gli apici.
Se questi apici sono doppi il quoting sarà debole, questo significa che i caratteri speciali verranno riconosciuti e interpretati.
Quali sono i caratteri speciali? Sono: $, `, \.
Se, invece, si utilizza uno quoting forte, generato dal singolo apice, i caratteri speciali non verrano riconosciuti né tanto meno interpretati.
NdR: Usi non semplici possono condurre a rompicapo: perchè non è possibile mettere un apice all’interno di un quoting forte ma è possibile mettere le virgolette all’interno di in un quoting debole ?

L'escaping è un metodo per effettuare il quoting di un singolo carattere. Per far questo si utilizza il carattere di escape, cioè \.
Tipi di escape sono:
\n: significa a capo

\r: significa invio

\t: significa tabulazione

\v: significa tabulazione verticale

\b: significa ritorno (backspace)

\": mantiene il significato letterale dei doppi apici

\$: mantiene il significato letterale del segno del dollaro (la variabile che segue \$ non verrà referenziata)

\\: mantiene il significato letterale della barra inversa

Re: Script Bash

Inviato: venerdì 2 marzo 2012, 23:59
da conoscenza
Costrutti condizionale if/then if/then/elif

Il costrutto if/then verifica che l'exit status di una condizione sia 0 (in Unix 0 significa successo per convenzione), e se questa ha esito positivo vengono eseguiti uno o più comandi.
Come altri linguaggi di programmazione, anche gli script bash, hanno la possibilità di avere costrutti if/then annidati.
Esempio di if/then:
if [ condizione-vera ]
then
comando 1
comando 2
...
else
comando 3
comando 4
...
fi
Esempio if/then/elif:
if [ condizione1 ]
then
comando1
comando2
comando3
elif [ condizione2 ] # Uguale a else if
then
comando4
comando5
else
comando-predefinito
fi
Esempio di if/then annidato:
if [ condizione1 ]
then
if [ condizione2 ]
then
fa-qualcosa # Ma solo se sia "condizione1" che "condizione2" sono vere.
fi
fi
NB: nelle condizioni vanno inseriti gli spazi!

Operatori di verifica sui file sono:
-e: il file esiste
-f: il file è un file regolare (non una directory o un file di dispositivo)
-s: il file ha dimensione superiore a zero
-d: il file è una directory
-b: il file è un dispositivo a blocchi (floppy, cdrom, ecc.)
-c: il file è un dispositivo a caratteri (tastiera, modem, scheda audio, ecc.)
-p: il file è una pipe
-h o -L: il file è un link simbolico
-r: il file ha il permesso di lettura (per l'utente che esegue la verifica)
-w: il file ha il permesso di scrittura (per l'utente che esegue la verifica)
-x: il file ha il permesso di esecuzione (per l'utente che esegue la verifica)
f1 -nt f2: il file f1 è più recente del file f2
f1 -ot f2: il file f1 è meno recente del file f2
f1 -ef f2: i file f1 e f2 sono hard link allo stesso file
!: "not", inverte il risultato delle precedenti opzioni di verifica (restituisce vero se la condizione è assente).

Confronti tra interi:
-eq: è uguale a --> Esempio:

Codice: Seleziona tutto

if [ "$a" -eq "$b" ]
-ne: è diverso (non uguale) da --> Esempio:

Codice: Seleziona tutto

 if [ "$a" -ne "$b" ]
-gt: è maggiore di --> Esempio:

Codice: Seleziona tutto

 if [ "$a" -gt "$b" ]
-ge: è maggiore di o uguale a --> Esempio:

Codice: Seleziona tutto

if [ "$a" -ge "$b" ]
-lt: è minore di --> Esempio:

Codice: Seleziona tutto

if [ "$a" -lt "$b" ]
-le: è minore di o uguale a --> Esempio:

Codice: Seleziona tutto

 if [ "$a" -le "$b" ]
<: è minore di (tra doppie parentesi) --> Esempio:

Codice: Seleziona tutto

 (("$a" < "$b"))
<=: è minore di o uguale a (tra doppie parentesi) --> Esempio:

Codice: Seleziona tutto

 (("$a" <= "$b"))
>: è maggiore di (tra doppie parentesi) --> Esempio:

Codice: Seleziona tutto

(("$a" > "$b"))
>=: è maggiore di o uguale a (tra doppie parentesi) --> Esempio:

Codice: Seleziona tutto

 (("$a" >= "$b"))
Confronto di stringhe:
=: è uguale a --> Esempio:

Codice: Seleziona tutto

if [ "$a" = "$b" ]
==: è uguale a --> Esempio:

Codice: Seleziona tutto

if [ "$a" == "$b" ]
NdR: "=" o "==" sono, in questo caso, sinonimi.
!=: è diverso (non uguale) da --> Esempio:

Codice: Seleziona tutto

if [ "$a" != "$b" ]
NB:All'interno del costrutto [[ ... ]] questo operatore esegue la ricerca di corrispondenza.
<: è inferiore a, in ordine alfabetico ASCII --> Esempio:

Codice: Seleziona tutto

if [[ "$a" < "$b" ]]

Codice: Seleziona tutto

if [ "$a" \< "$b" ]
NB: Si noti che "<" necessita dell'escaping nel costrutto [ ].
>: è maggiore di, in ordine alfabetico ASCII --> Esempio:

Codice: Seleziona tutto

if [[ "$a" > "$b" ]]

Codice: Seleziona tutto

if [ "$a" \> "$b" ]
NB: Si noti che ">" necessita dell'escaping nel costrutto [ ].
-z: la stringa è "nulla", cioè, ha lunghezza zero
-n: la stringa non è "nulla".
NB: L'operatore -n richiede assolutamente il quoting della stringa all'interno delle parentesi quadre. Per l'operatore -z potrebbe funzionare, ma è meglio usare anche questo caso il quoting. --> Esempi:

Codice: Seleziona tutto

if [ -z "$stringa1" ]

Codice: Seleziona tutto

if [ -n "$stringa1" ]
Confronti composti:
&& o -a: fa l'AND logico tra le due espressioni.
|| o -o: fa l'OR logico tra le due espressioni.

Re: Script Bash

Inviato: sabato 3 marzo 2012, 0:00
da conoscenza
Cicli for, while e until

Il ciclo for viene iterato per passi conosciuti a priori.
La sintassi del ciclo for è del tipo
for arg in [lista]
do
comando(i)...
done
Ad ogni passo del ciclo la variabile "arg" assume il valore di ognuna delle successive variabili elencate in [lista].
Si noti che agli argomenti presenti in lista viene applicato il quoting, per evitari possibili suddivisioni errate. Inoltre gli argomenti in [lista] possono utilizzare il carattere jolly, *.

È Possibile, ma non totalmente corretto, usare il ciclo for con una sintassi simile a quella del C.
Ad esempio il codice per uno script bash che conta fino a 5 è:
LIMITE=5

for ((a=1; a <= LIMITE; a++)) # Doppie parentesi, e "LIMITE" senza "$".
do
echo -n "$a "
done

exit 0
Ciclo while
I passi del ciclo while, a differenza del ciclo for, non è noto a priori. Continuerà a iterare fino a quando la condizione non resterà vera.
La sintassi è del tipo:
while [ condizione ]
do
comando(i)...
done
o ancor meglio usando il costrutto a doppie parentesi quadre:
while [[ condizione ]]
do
comando(i)...
done
NdR: si noti l'uso degli spazi nelle condizioni, come quello usato per il costrutto if/then.

Il ciclo while può richiamare, al posto della condizione, una funzione.
Ad esempio un pseudo-codice sarebbe:
condizione ()
{
codice
funzione
che fa
qualcosa
}
while condizione
do
comando(i)...
done
Ciclo until
Il costrutto until è simile al costutto while, la differenza sta nel fatto che until viene eseguito fin tanto che la condizione resta falsa (in while la condizione deve essere vera).
Il pseudo-codice di until è:
until [ condizione-falsa ]
do
comando(i)...
done

Re: Script Bash

Inviato: sabato 3 marzo 2012, 0:02
da conoscenza
Break e continue

Anche negli script bash è possibile utilizzare i comandi di controllo break e continue.
Il comando break, per chi non lo sapesse, permette di interrompere il ciclo (uscendo), mentre continue provoca il salto all'iterazione (ripetendo) successiva, tralasciando tutti i restanti comandi di quel particolare passo del ciclo.
Sia break che continue, possono avere un parametro che indica a quale livello deve intervenire.
Quindi "break N" interrompe il ciclo di livello N, mentre "continue N" salta tutte le restanti iterazioni del ciclo in cui si trova e continua con l'iterazione successiva del ciclo N di livello superiore.

- Costrutti case -
Il case indirizza il flusso dello script verso uno dei diversi blocchi di codice, in base alle condizioni di verifica. È uno strumento adatto a creare menu.
Lo psedo-codice di case è:
case "$variabile" in

"$condizione1" )
comando...
;;

"$condizione2" )
comando...
;;

esac
NdR:
1) il quoting delle variabili non è obbligatorio;
2) ogni riga di verifica termina con una parentesi tonda chiusa ")";
3) ciascun blocco di istruzioni termina con un doppio punto e virgola ";;";
4) per raccogliere tutti i casi restanti non esplicitati si puù uare il comando jolly "*";
5) l'intero blocco case termina con esac.

Re: Script Bash

Inviato: sabato 3 marzo 2012, 0:04
da conoscenza
Sostituzione di un comando

Questo passo significa riassegnare il risultato di un comando, o anche di più comandi, ad un comando; connettendo l'output di un comando ad un altro contesto.
La forma classica è quella di usare gli apici inversi (si ottengono con Alt GR + '), ad esempio:
comando1 opzioni1 `comando2 (opzioni2)`
In questo caso verrà passato a comando1 l'output di comando2 che, a sua volta, è stato eseguito con le sue opzioni.
Ovviamente, nulla vieta di usare anche per comando1 delle opzioni.
Esiste anche una forma alternativa agli apici inversi.
Ed è quella di usare una sintassi del tipo:
$(comando opzioni)
Nell'utilizzo di questa sintassi si deve fare attenzione però alla suddivsione delle parole. Riporto i casi di suddivisione per gli argomenti:
comando1 `comando2 a b` ---> due argomenti: a e b;

comando1 "`comando2 a b`" ---> un argomento: "a b"

comando1 "`comando2`" ---> un argomento vuoto

comando1 `comando2` ---> nessun argomento
NdR:
1) La sostituzione di comando nella forma $(...) gestisce la doppia barra inversa in modo diverso che non nella forma `...`.
Vediamo gli esempi:
bash$ echo `echo \\`
outout:
bash$ echo $(echo \\)
output: \
Come si vede nel primo caso non viene restituito nulla, mentre nel secondo caso si vede regolarmente il carattere \.

2) La sostituzione di comando nella forma $(...) consente l'annidamento di più comandi.
Ad esempio:
conteggio_parole=$( wc -w $(ls -l | awk '{print $9}') )
Tuttavia, l' annidamento è possibile anche con gli apostrofi inversi, effettuando, però, l'escaping di quelli interni.