Bash scripting - istruzioni composte: differenze tra le versioni

m
correzione
m (aggiunto link)
m (correzione)
 
(2 versioni intermedie di 2 utenti non mostrate)
Riga 1: Riga 1:
{{Bash scripting}}
{{Bash scripting}}
=Istruzioni composte=
__TOC__
Sono istruzioni composte tutte le istruzioni che possono contenere al loro interno altre istruzioni. Tipicamente sono introdotte e terminate da parole chiave (''keywords''), in quanto definiscono regole speciali al loro interno, spesso facendo uso anche di parole riservate che agiscono come istruzioni.
Sono istruzioni composte tutte le istruzioni che possono contenere al loro interno altre istruzioni. Tipicamente sono introdotte e terminate da parole chiave (''keywords''), in quanto definiscono regole speciali al loro interno, spesso facendo uso anche di parole riservate che agiscono come istruzioni.


Per esempio <code>if</code> e <code>for</code> sono due istruzioni composte (e due ''keywords''):
Per esempio <code>if</code> e <code>for</code> sono due istruzioni composte (e due ''keywords''):
* <code>if</code> è già stata trattata assieme all'uso di <code>[ ... ]</code> nei [[Bash scripting - comandi essenziali#Condizioni | comandi essenziali]], utile anche per le condizioni del ciclo <code>while</code>;
* <code>if</code> è già stata trattata assieme all'uso di <code>[ ... ]</code> nei [[Bash scripting - comandi essenziali#Condizioni | comandi essenziali]], utile anche per le condizioni del ciclo <code>while</code>;
* <code>for</code> è già stato trattato nell'[[Bash scripting - variabili - stringhe#Assegnazione con ciclo | assegnazione con ciclo]], con la sintassi tipica di ''for each'' di alcuni linguaggi di programmazione e l'unica prevista da ''POSIX''.
* <code>for</code> è già stato trattato nell'[[Bash scripting - variabili - stringhe#Assegnazione con ciclo | assegnazione con ciclo]], con la sintassi tipica di ''for each'' di alcuni linguaggi di programmazione e l'unica prevista da [[POSIX]].


==Cicli==
== Cicli ==
Con <code>while</code> è possibile eseguire un blocco di comandi se un comando ha successo e ripeterne l'esecuzione fintanto che il comando continua ad avere successo. Proprio come <code>if</code>, <code>while</code> è un'istruzione accompagnata spesso da <code>[...]</code>, utilizzato come comando di cui valutare l'exit status.
Con <code>while</code> è possibile eseguire un blocco di comandi se un comando ha successo e ripeterne l'esecuzione fintanto che il comando continua ad avere successo. Proprio come <code>if</code>, <code>while</code> è un'istruzione accompagnata spesso da <code>[...]</code>, utilizzato come comando di cui valutare l'exit status.


Riga 26: Riga 26:
   printf %s "Inserisci intero > 0 e premi INVIO: "
   printf %s "Inserisci intero > 0 e premi INVIO: "
   # assegna l'input dell'utente a $num
   # assegna l'input dell'utente a $num
   read num
   read -r num
done
done
printf %s\\n "Hai inserito: ${num}"
printf %s\\n "Hai inserito: ${num}"
Riga 76: Riga 76:
E non è una svista la mancanza di '''$''' davanti al nome delle variabili all'interno di <code>((...))</code>. Tale sintassi è supportata anche nell'espansione aritmetica intera, ma non è prevista da ''POSIX'', e quindi non è mai stata usata in questa guida.
E non è una svista la mancanza di '''$''' davanti al nome delle variabili all'interno di <code>((...))</code>. Tale sintassi è supportata anche nell'espansione aritmetica intera, ma non è prevista da ''POSIX'', e quindi non è mai stata usata in questa guida.


==Composizione di comandi con pipe==
== Composizione di comandi con pipe ==
Una ''pipe'' collega due comandi, trattando l'output generato dal primo come input per il secondo, in modo da svolgere funzioni più complesse tramite la composizione di comandi che si occupano di funzioni più limitate. Ed è una delle caratteristiche di ''Unix'' che ogni comando debba svolgere un'unica funzione nel modo migliore possibile, permettendo la comunicazione con l'utente o un altro comando attraverso un flusso di testo, considerato un'interfaccia universale.
Una ''pipe'' collega due comandi, trattando l'output generato dal primo come input per il secondo, in modo da svolgere funzioni più complesse tramite la composizione di comandi che si occupano di funzioni più limitate. Ed è una delle caratteristiche di ''Unix'' che ogni comando debba svolgere un'unica funzione nel modo migliore possibile, permettendo la comunicazione con l'utente o un altro comando attraverso un flusso di testo, considerato un'interfaccia universale.


Riga 107: Riga 107:
</pre>
</pre>


===Output dei comandi e carattere ASCII n. 0===
=== Output dei comandi e carattere ASCII n. 0 ===
Una variabile non può contenere il carattere ASCII n. 0, che è usato per indicare la fine della stringa. Non potendo gestire direttamente il carattere ASCII n. 0, questo non può essere presente nell'espansione di un comando, ma dev'essere riservato ai soli comandi mediante l'uso di una o più pipe.
Una variabile non può contenere il carattere ASCII n. 0, che è usato per indicare la fine della stringa. Non potendo gestire direttamente il carattere ASCII n. 0, questo non può essere presente nell'espansione di un comando, ma dev'essere riservato ai soli comandi mediante l'uso di una o più pipe.


Riga 129: Riga 129:
È ovviamente un metodo molto inefficiente, ma l'unico permesso per memorizzare in una variabile. In alcuni casi potrebbe essere preferibile una codifica esadecimale o ottale, ancora più inefficiente quanto a spazio occupato, ma più semplici da manipolare dalla shell.
È ovviamente un metodo molto inefficiente, ma l'unico permesso per memorizzare in una variabile. In alcuni casi potrebbe essere preferibile una codifica esadecimale o ottale, ancora più inefficiente quanto a spazio occupato, ma più semplici da manipolare dalla shell.


====Nomi di file con caratteri non comuni====
==== Nomi di file con caratteri non comuni ====
Questo carattere è utile perché nemmeno i file possono averlo nel proprio nome, mentre invece permettono caratteri jolly (*, ?, ...), come già visto con le espansioni di percorso, e potrebbero contenere perfino il carattere "a capo".
Questo carattere è utile perché nemmeno i file possono averlo nel proprio nome, mentre invece permettono caratteri jolly (*, ?, ...), come già visto con le espansioni di percorso, e potrebbero contenere perfino il carattere "a capo".


Riga 158: Riga 158:
</pre>
</pre>


====Comando find e carattere ASCII n. 0====
==== Comando find e carattere ASCII n. 0 ====
Un abbinamento comune al comando esterno GNU <code>find</code> (dotato dell'opzione -print0) è il comando esterno GNU <code>xargs</code> (dotato dell'opzione -0):
Un abbinamento comune al comando esterno GNU <code>find</code> (dotato dell'opzione -print0) è il comando esterno GNU <code>xargs</code> (dotato dell'opzione -0):
<pre>
<pre>
Riga 169: Riga 169:
<pre>
<pre>
find /percorso -opzione1 ... -opzioneN -print0 |
find /percorso -opzione1 ... -opzioneN -print0 |
     while read -d $'\000' file
     while read -r -d $'\000' file
     do
     do
         # posso usare "$file"
         # posso usare "$file"
Riga 182: Riga 182:
</pre>
</pre>


==Concatenazione e blocchi di comandi==
== Concatenazione e blocchi di comandi ==
Più comandi, anche contenenti redirezioni, possono essere concatenati per formarne di più complessi. L'operatore di concatenazione può essere anche l'ultimo di una riga, per facilitare la leggibilità del codice.
Più comandi, anche contenenti redirezioni, possono essere concatenati per formarne di più complessi. L'operatore di concatenazione può essere anche l'ultimo di una riga, per facilitare la leggibilità del codice.


Riga 217: Riga 217:
; <code>( ... )</code> : esegue il blocco di comandi in una subshell (le variabili vengono ripristinate al loro valore precedente, alla fine del blocco).
; <code>( ... )</code> : esegue il blocco di comandi in una subshell (le variabili vengono ripristinate al loro valore precedente, alla fine del blocco).


===Catturare l'exit status===
=== Catturare l'exit status ===
Per catturare lo stato d'uscita di un comando appena eseguito è sufficiente espandere la variabile speciale <code>$?</code>, come già visto. Tuttavia in caso di fallimento del comando, il controllo effettuato via <code>$?</code> avverrebbe soltanto '''dopo''' un blocco con errore (si veda la parte introduttiva sul [[Bash scripting - introduzione#Debug integrato | debug]]).
Per catturare lo stato d'uscita di un comando appena eseguito è sufficiente espandere la variabile speciale <code>$?</code>, come già visto. Tuttavia in caso di fallimento del comando, il controllo effettuato via <code>$?</code> avverrebbe soltanto '''dopo''' un blocco con errore (si veda la parte introduttiva sul [[Bash scripting - introduzione#Debug integrato | debug]]).


Riga 227: Riga 227:
</pre>
</pre>


===Condizioni complesse===
=== Condizioni complesse ===
Anche se '''bash''' dispone di altri metodi per unire condizioni più semplici, è possibile utilizzare la sintassi ''POSIX'', concatenando più comandi <code>[...]</code> tramite gli operatori logici ''AND'' e ''OR'' logici (<code>&&</code> e <code>||</code>, rispettivamente) e raggruppandoli con <code>{ ... ; }</code>. Inoltre gli operatori logici sono più efficienti, in quanto verrebbero eseguiti soltanto i comandi necessari a valutare la condizione, e si possono usare per evitare errori.
Anche se '''bash''' dispone di altri metodi per unire condizioni più semplici, è possibile utilizzare la sintassi [[POSIX]], concatenando più comandi <code>[...]</code> tramite gli operatori logici ''AND'' e ''OR'' logici (<code>&&</code> e <code>||</code>, rispettivamente) e raggruppandoli con <code>{ ... ; }</code>. Inoltre gli operatori logici sono più efficienti, in quanto verrebbero eseguiti soltanto i comandi necessari a valutare la condizione, e si possono usare per evitare errori.


Per esempio:
Per esempio:
Riga 253: Riga 253:
[ -f "$var" ] && [ -r "$var" ] && [ -x "$var" ]
[ -f "$var" ] && [ -r "$var" ] && [ -x "$var" ]


# Controlla che la directory esista e sia possibile listarne il contenuto
# Controlla che la directory esista e sia possibile ottenere una lista del suo contenuto
# (per sapere se un file esiste nella directory)
# (per sapere se un file esiste nella directory)
[ -d "$var" ] && [ -r "$var" ]
[ -d "$var" ] && [ -r "$var" ]


# Controlla che la directory esista e sia possibile accederne il contenuto
# Controlla che la directory esista e sia possibile accedere al suo contenuto
# (leggendo o scrivendo i file, se i loro permessi lo consentono)
# (leggendo o scrivendo i file, se i loro permessi lo consentono)
[ -d "$var" ] && [ -x "$var" ]
[ -d "$var" ] && [ -x "$var" ]


# Controlla che la directory esista e sia possibile listarne e accederne il contenuto
# Controlla che la directory esista e sia possibile ottenere una lista e accedere al suo contenuto
[ -d "$var" ] && [ -r "$var" ] && [ -x "$var" ]
[ -d "$var" ] && [ -r "$var" ] && [ -x "$var" ]


# Controlla che la directory esista e sia possibile creare e cancellare dei file noti
# Controlla che la directory esista e sia possibile creare e cancellare dei file noti
# (permesso di attraversamento + scrittura)
# (permesso di accesso + scrittura)
[ -d "$var" ] && [ -x "$var" ] && [ -w "$var" ]
[ -d "$var" ] && [ -x "$var" ] && [ -w "$var" ]


# Controlla che la directory esista e sia possibile cancellarne il contenuto (non noto)
# Controlla che la directory esista e sia possibile cancellarne il contenuto (non noto)
# (permesso di lettura, per listarne il contenuto, + permessi del caso precedente)
# (permesso di lettura, per ottenere una lista del suo contenuto, + permessi del caso precedente)
[ -d "$var" ] && [ -r "$var" ] && [ -x "$var" ] && [ -w "$var" ]
[ -d "$var" ] && [ -r "$var" ] && [ -x "$var" ] && [ -w "$var" ]
</pre>
</pre>
Riga 299: Riga 299:
</pre>
</pre>


==Condizioni avanzate con pattern matching==
== Condizioni avanzate con pattern matching ==
Anche se si possono costruire condizioni arbitrarie sfruttando le sole istruzioni <code>[...]</code> con concatenazioni, raggruppamenti ed espansioni di parametro, tramite l'istruzione composta <code>case</code> è possibile scrivere confronti complessi molto più facilmente.
Anche se si possono costruire condizioni arbitrarie sfruttando le sole istruzioni <code>[...]</code> con concatenazioni, raggruppamenti ed espansioni di parametro, tramite l'istruzione composta <code>case</code> è possibile scrivere confronti complessi molto più facilmente.


Viene selezioanta per i confronti una stringa, di solito una variabile quotata, e diversi pattern con la stessa sintassi ammessa per l'espansione di percorso (''globbing''), eseguendo soltanto il blocco di comandi relativo alla prima corrispondenza trovata, e ignorando gli altri.
Viene selezionata per i confronti una stringa, di solito una variabile quotata, e diversi pattern con la stessa sintassi ammessa per l'espansione di percorso (''globbing''), eseguendo soltanto il blocco di comandi relativo alla prima corrispondenza trovata, e ignorando gli altri.


La shell '''bash''' ha diverse espansioni rispetto a ''POSIX'', e anche l'uso della parola riservata <code>select</code>, ma questa sezione si limita alla sintassi ''POSIX'', che è anche più comprensibile per chi è abituato ad altri linguaggi di programmazione.
La shell '''bash''' ha diverse espansioni rispetto a ''POSIX'', e anche l'uso della parola riservata <code>select</code>, ma questa sezione si limita alla sintassi ''POSIX'', che è anche più comprensibile per chi è abituato ad altri linguaggi di programmazione.


I pattern devono consistere di un'unica stringa, o più stringhe separate dal carattere <code>|</code>, e a eccezione dei caratteri speciali per il globbing vanno quotati per evitare espansioni accidentali o pattern non voluti.
I pattern devono consistere di un'unica stringa, o più stringhe separate dal carattere <code>|</code> e, a eccezione dei caratteri speciali per il globbing, vanno quotati per evitare espansioni accidentali o pattern non voluti.


Sintassi:
Sintassi:
Riga 359: Riga 359:
</pre>
</pre>


===Esempio: controllo sul percorso di un file===
=== Esempio: controllo sul percorso di un file ===
Controllare il percorso di un file, e aggiungere quello relativo se manca:
Controllare il percorso di un file, e aggiungere quello relativo se manca:
<pre>
<pre>
Riga 384: Riga 384:
</pre>
</pre>


===Parsing degli argomenti===
=== Parsing degli argomenti ===
Si effettua con il comando '''getopts''' (da non confondersi con <code>getopt</code>, un comando esterno più avanzato non ''POSIX'' utilizzato allo stesso scopo).
Si effettua con il comando '''getopts''' (da non confondersi con <code>getopt</code>, un comando esterno più avanzato non ''POSIX'' utilizzato allo stesso scopo).


Riga 398: Riga 398:
* il carattere delle opzioni che richiede un argomento ausiliario va seguito dal carattere <code>:</code> e l'argomento sarà assegnato alla variabile <code>$OPTARG</code>, se trovato, altrimenti verrà stampato un errore (se non disabilitati) e la variabile scelta conterrà il carattere <code>?</code>;
* il carattere delle opzioni che richiede un argomento ausiliario va seguito dal carattere <code>:</code> e l'argomento sarà assegnato alla variabile <code>$OPTARG</code>, se trovato, altrimenti verrà stampato un errore (se non disabilitati) e la variabile scelta conterrà il carattere <code>?</code>;
* la variabile <code>$OPTIND</code> è aggiornata a ogni esecuzione di <code>getopts</code> per tenere traccia dell'indice dell'ultimo parametro letto partendo da 1 (per esempio $OPTIND a 5 significa che sono state lette le variabili speciali <code>$1 ... $4</code>, infatti <code>$4</code> è in quinta posizione);
* la variabile <code>$OPTIND</code> è aggiornata a ogni esecuzione di <code>getopts</code> per tenere traccia dell'indice dell'ultimo parametro letto partendo da 1 (per esempio $OPTIND a 5 significa che sono state lette le variabili speciali <code>$1 ... $4</code>, infatti <code>$4</code> è in quinta posizione);
* tutto ciò che non è un'opzione o un argomento di un'opzione, e tutto ciò che segue <code>--</code>, è considerato una lista di argomenti. Per accederli è necessario effettuare lo shift (con il comando <code>shift</code>) di tutte le stringhe già lette, ossia: $OPTIND - 1.
* tutto ciò che non è un'opzione o un argomento di un'opzione, e tutto ciò che segue <code>--</code>, è considerato una lista di argomenti. Per accedervi è necessario effettuare lo shift (con il comando <code>shift</code>) di tutte le stringhe già lette, ossia: $OPTIND - 1.


====Esempio: script con parsing degli argomenti====
==== Esempio: script con parsing degli argomenti ====
<pre>
<pre>
#! /bin/bash
#! /bin/bash
3 581

contributi