Bash scripting: differenze tra le versioni

riscritta parte sulla redirezione (ma è ancora incompleta e mancano i file descriptor)
m (limite dei 30 KB... sigh...)
(riscritta parte sulla redirezione (ma è ancora incompleta e mancano i file descriptor))
Riga 11: Riga 11:
Un nome di variabile ammette soltanto caratteri alfabetici (maiuscoli e minuscoli), l'underscore ('_') e numeri (non in prima posizione). E il suo contenuto si accede con <code>${nome}</code> oppure con la forma abbreviata <code>$nome</code>.
Un nome di variabile ammette soltanto caratteri alfabetici (maiuscoli e minuscoli), l'underscore ('_') e numeri (non in prima posizione). E il suo contenuto si accede con <code>${nome}</code> oppure con la forma abbreviata <code>$nome</code>.


La forma abbreviata assume che il nome della variabile sia composto da tutti i caratteri validi incontrati. Per esempio <code>"$nome$cognome"</code> (due variabili concatenate) è equivalente a <code>"${nome}${cognome}"</code>, ma <code>"$nome_$cognome"</code> non lo è a <code>"${nome}_${cognome}"</code> perché <code>nome_</code> (con underscore finale) sarebbe un nome valido. Con la concatenazione di variabili è preferibile accedere alle variabili con le graffe, o in alternativa delimitarle una a una dalle virgolette (<code>"$nome"_"$cognome"</code>).
La forma abbreviata assume che il nome della variabile sia composto da tutti i caratteri validi incontrati. Per esempio la concatenazione <code>"$nome$cognome"</code> è equivalente a <code>"${nome}${cognome}"</code>, ma <code>"$nome_$cognome"</code> non lo è a <code>"${nome}_${cognome}"</code> perché <code>nome_</code> (con underscore finale) sarebbe un nome valido. Con la concatenazione di variabili è preferibile accedere alle variabili con le graffe.


=== Assegnazioni ===
=== Assegnazioni ===
Non si deve usare il <code>'''$'''</code> davanti alla variabile a cui assegnare:
Non si deve usare il <code>'''$'''</code> davanti alla variabile a cui assegnare:
<pre>
<pre>
  var=stringa                        # assegno un valore (una stringa senza spazi e caratteri speciali)
  var=stringa                        # assegno una stringa senza spazi e caratteri speciali
  var="stringa con spazi"            # assegno una stringa con spazi (con caratteri speciali preceduti da '\')
  var="stringa con spazi"            # assegno una stringa con spazi (e caratteri speciali preceduti da '\')
  var='stringa senza apici'          # assegno una stringa contenente spazi e caratteri speciali (ma non apici)
  var='stringa senza apici'          # assegno una stringa contenente spazi e caratteri speciali (ma non apici)
  var=$var2                          # assegno un'altra variabile
  var=$var2                          # assegno un'altra variabile
  var=${var2}                        # equivalente a sopra
  var=${var2}                        # come sopra
  var="$var2"                        # equivalente a sopra (non serve quotare nelle assegnazioni)
  var="$var2"                        # come sopra (non serve quotare nelle assegnazioni)
  var='$var2'                        # si assegna letteralmente $var2 (e non il suo contenuto)
  var='$var2'                        # assegno letteralmente $var2 (e non il suo contenuto)
  var="\$var2"                        # come sopra, perché $ è preceduto da \
  var="\$var2"                        # come sopra, perché $ è preceduto da \
  var="${var1} testo ${var2}_${var3}" # assegno una concatenazione di variabili e stringhe
  var="${var1} testo ${var2}_${var3}" # assegno una concatenazione di variabili e stringhe
Riga 160: Riga 160:
Alcuni caratteri hanno un valore speciale per la shell, per consentirne le espansioni (di variabile, parametro, comando, percorso, ecc...). Di conseguenza se si intende scrivere un carattere speciale senza espanderlo, è necessario comunicarlo alla shell facendolo precedere da un carattere di escape '<code>\</code>' oppure racchiudendolo tra apici o virgolette (a seconda dell'espansione da disattivare).
Alcuni caratteri hanno un valore speciale per la shell, per consentirne le espansioni (di variabile, parametro, comando, percorso, ecc...). Di conseguenza se si intende scrivere un carattere speciale senza espanderlo, è necessario comunicarlo alla shell facendolo precedere da un carattere di escape '<code>\</code>' oppure racchiudendolo tra apici o virgolette (a seconda dell'espansione da disattivare).


Una stringa non racchiusa tra apici o tra virgolette ha i seguenti caratteri speciali: <code>'</code>, <code>"</code>, <code>`</code>, <code>$</code>, <code>\</code>, <code>{</code>, <code>}</code>, <code>[</code>, <code>]</code>, <code>*</code>, <code>?</code>, <code>~</code>, <code>(</code>, <code>)</code>, <code>;</code> e <code>#</code>. Se non preceduti dal carattere di escape <code>\</code> possono in base ai caratteri immediatamente successivi essere espansi, considerati parte di un nuovo comando o tralasciati come commenti. Questa sezione non è esaustiva e non considera tutte le eccezioni, ma consiglia degli accorgimenti che si possono sempre seguire per ridurre la necessità dell'escape.
Una stringa non racchiusa tra apici o tra virgolette ha i seguenti caratteri speciali: <code>' " ` $ \ { } [ ] * ? ~ ( ) ; & | #</code>
<br/>In determinate circostanze, se non preceduti dal carattere di escape <code>\</code>, possono essere: espansi, eseguiti in background, considerati parte di un nuovo comando o essere tralasciati come commenti. Questa sezione non è esaustiva e non considera tutte le eccezioni, ma consiglia degli accorgimenti che si possono sempre seguire per ridurre la necessità dell'escape.


Inoltre gli spazi (comprendendo tabulazioni e a capo) non quotati (con apici o virgolette) e non preceduti dal carattere di escape <code>\</code> vengono compressi.
Inoltre gli spazi (comprese le tabulazioni) non quotati con apici o virgolette, e non preceduti dal carattere di escape <code>\</code>, vengono compressi.


Per esempio:
Per esempio:
Riga 202: Riga 203:
===Racchiudere tra apici===
===Racchiudere tra apici===
Con gli apici (apostrofi) si riducono i caratteri speciali a uno soltanto, lo stesso apice, rappresentando la stringa per il suo solo valore letterale e impedendo tutte le espansioni:
Con gli apici (apostrofi) si riducono i caratteri speciali a uno soltanto, lo stesso apice, rappresentando la stringa per il suo solo valore letterale e impedendo tutte le espansioni:
<pre>echo '$PATH "" \ `ls ..` \$HOME ~ * .[a-z]*'  # stampa la stringa tra apici, così com'è scritta</pre>
<pre>echo '$PATH "" \ `ls ..` \$HOME ~ * .[a-z]*'  # stampa la stringa tra apici, letteralmente</pre>


Lo svantaggio è che non esiste un carattere di escape:
Lo svantaggio è che non esiste un carattere di escape:
<pre>echo 'L'\''albero di... ' # stampa "L'albero di..." (l'accento non può essere racchiuso tra apici e va preceduto da \)</pre>
<pre>echo 'L'\''albero di... ' # stampa "L'albero di..." (l'accento non può essere racchiuso tra apici)</pre>


===Quotare (tra virgolette)===
===Quotare (tra virgolette)===
Racchiudere tra virgolette ogni stringa è raccomandabile, anche se non sempre necessario, così da ridurre drasticamente il numero di caratteri speciali a cui pensare, permettendo allo stesso tempo l'espansione sicura delle variabili e dei comandi. I soli caratteri speciali rimasti sono <code>$</code>, <code>`</code> (ma non l'apice), <code>"</code> e <code>\</code>, che devono essere preceduti dal carattere di escape <code>\</code>. Le sole espansioni permesse all'interno di una stringa quotata sono di variabile e parametro (attraverso <code>$</code>) e quelle di comando (attraverso <code>$(...)</code> o <code>`...`</code>).
Racchiudere tra virgolette ogni stringa è raccomandabile, anche se non sempre necessario, così da ridurre il numero di caratteri speciali a cui pensare, permettendo allo stesso tempo l'espansione sicura delle variabili e dei comandi. I soli caratteri speciali rimasti sono <code>$</code>, <code>`</code> (ma non l'apice), <code>"</code> e <code>\</code>, che devono essere preceduti dal carattere di escape <code>\</code>. Le sole espansioni permesse all'interno di una stringa quotata sono di variabile/parametro e quelle di comando.


Per esempio:
Per esempio:
Riga 226: Riga 227:
<pre>`comando`</pre>  
<pre>`comando`</pre>  


L'output del comando consiste in zero, una o più stringhe, in base agli spazi presenti nell'output prodotto e in maniera analoga all'espansione a cui sono soggette le variabili. Per trasformare l'output di un comando in una singola stringa è necessario che l'espansione di comando sia quotata, con l'eccezione dell'assegnazione a una variabile.
L'output del comando consiste in zero, una o più stringhe: in base agli spazi presenti nell'output prodotto, e in maniera analoga all'espansione a cui sono soggette le variabili. Per trasformare l'output di un comando in una singola stringa è necessario che l'espansione di comando sia quotata, con l'eccezione dell'assegnazione a una variabile.


Esempi di assegnazione:
Esempi di assegnazione:
Riga 240: Riga 241:
</pre>
</pre>


Esecuzione dei comandi e passaggio come argomento del loro output:
Passaggio dell'output dei comandi come argomento:
<pre>
<pre>
# stampa stati
# stampa stati
Riga 392: Riga 393:
</pre>
</pre>


==Concatenazione e redirezione==
==Concatenazione==
; <code>&&</code> : operatore logico AND, il secondo comando verrà eseguito solo se il primo avrà esito positivo
; <code>&&</code> : operatore logico AND, il secondo comando verrà eseguito solo se il primo avrà esito positivo
; <code>;</code> : separatore di comandi, il secondo comando verrà eseguito in ogni caso (in uno script è equivalente a un "a capo" e questa è la concatenazione di default)
; <code>;</code> : separatore di comandi, il secondo comando verrà eseguito in ogni caso (in uno script è equivalente a un "a capo" e questa è la concatenazione di default)
; <code>&</code> : separatore che lancia il comando precedente in background (non c'è exit status e non riceve input da tastiera)
<pre>
cd /percorso/dir && comando
</pre>


$ cd ... && echo done
Attenzione invece alla '''pericolosità''' di:
$ cd ... ; echo done
<pre>
cd /tmp/tmpdir # cambia la cartella corrente in /tmp/tmpdir
# ma se fallisce, quello successivo verrebbe eseguito comunque!
rm -- ./*      # cancella tutti i file nella directory corrente
</pre>


Nel caso specifico di un'applicazione che resta in esecuzione il secondo comando non verrà eseguito finché il
; <code>||</code> : operatore logico OR, il secondo comando è eseguito solo se il primo ha effetto negativo (si può usare anche dopo una sequenza di &&, perché ha priorità inferiore):
primo non sarà terminato, in questo caso si usa <code>'''&'''</code> e saranno eseguiti entrambi in quanto il primo comando viene mandato in background; prendiamo xterm come esempio:


$ xterm && xterm -rv
; <code>{ ... ; }</code> : esegue un blocco di comandi (dopo l'ultimo servono ";" o un "a capo"). È usata nelle funzioni ed è utile per concatenare && e ||:
$ xterm ; xterm -rv
<pre>
$ xterm & xterm -rv
# interrompe la catena se un comando fallisce
cd /tmp/tmpdir &&
rm -- ./* &&
rmdir -- /tmp/tmpdir || {
  # il blocco è eseguito solo se un comando fallisce
  retval=$?
  echo "ERRORE (exit status: $retval)" >&2
  exit $retval
}
</pre>


; <code>|</code> : pipe, passa l'output del comando che la precede come input del comando che la segue
; <code>( ... )</code> : esegue il blocco di comandi in una subshell (le variabili vengono ripristinate al loro valore precedente, alla fine del blocco).


$ ls -A1 | less
==Redirezione==
 
Alcune comuni redirezioni:
; <code>||</code> : operatore logico OR, restituisce esito positivo se almeno una delle condizioni di verifica valutate è vera
; <code>> file</code> scrive l'output sul file (troncandolo, se esiste);
; <code>>> file</code> aggiunge al file (creandolo, se non esiste);
; <code>< file</code> legge l'input dal file;
; <code>>&2</code> scrive l'output sullo standard error;
; <code>2> file</code> scrive lo standard error sul file (per aggiungere: 2>>);
; <code>2>&1</code> scrive lo standard error sullo standard output;
; <code>&> file</code> invia standard output ed error sul file (per aggiungere: &>>);
; <code>comando1 | comando2</code> : pipe che passa l'output del comando1 al comando2 come input. I comandi (anche l'ultimo) sono eseguiti in una subshell.


Esempi:
<pre>
<pre>
$ if [ -f ~/.bashrc ] || [ -d ~/.config ]; then echo 'w00t!'; else echo 'no such file or directory'; fi
comando &> /dev/null    # non stampa niente a schermo
 
comando > /dev/null 2>&1 # equivalente (POSIX)
$ if [ -f ~/.bashrc ] || [ -d ~/.configs ]; then echo 'w00t!'; else echo 'no such file or directory'; fi


$ if [ -f ~/.bash ] || [ -d ~/.configs ]; then echo 'w00t!'; else echo 'no such file or directory'; fi
# filtra le occorrenze di video
dmesg | grep -i video
</pre>
</pre>
* [http://www.tldp.org/LDP/abs/html/special-chars.html Advanced Bash-Scripting Guide: Special Characters]
Dirige output di comando su file:
$ man xterm > xterm.txt
Dirige output di errore su file:
$ xterm 2> xterm-errors.log
Entrambi su file diversi:
$ xterm > xterm_out.log 2> xterm_err.log
Entrambi sullo stesso file:
$ xterm &> xterm.log
Entrambi sullo stesso file, alternativa:
$ xterm > xterm.log 2>&1
Appende nuovo testo a quello già presente in un file:
$ man uxterm >> xterm.txt
Cancella contenuto di un file:
$ :> xterm.txt


===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 sul 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 sul debug).


Per evitare che un blocco abbia un exit status diverso da zero, si possono usare le concatenazioni (oppure un <code>if</code>):
Per evitare che un blocco abbia un exit status diverso da zero, si possono usare le concatenazioni <code>&&</code> e <code>||</code> (oppure un <code>if</code>):
<pre>
<pre>
comando &&
comando &&
Riga 446: Riga 454:
status=$?  # se sbagliato
status=$?  # se sbagliato
</pre>
</pre>
I comandi precedenti costituiscono un unico blocco, sempre corretto, mentre invece:
<pre>
comando            # questo comando è anche un blocco
status=$?
comando; status=$? # sono sempre due blocchi distinti</pre>


===Output dei comandi e carattere ASCII n. 0===
===Output dei comandi e carattere ASCII n. 0===
Riga 465: Riga 467:
</pre>
</pre>


L'utilità di questo carattere si deve in particolare al fatto che nemmeno i file possono averlo nel proprio nome, mentre invece permettono caratteri jolly (*, ?, ...) come abbiamo 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".


L'espansione di percorso funziona normalmente, anche in presenza di "a capo", ma potrebbero sorgere problemi sfruttando l'espansione di comando. Per esempio con il comando esterno <code>find</code>, utilizzato per effettuare ricerche in modo ricorsivo, e che di default restituisce tutti i file trovati che soddisfano determinate condizioni stampandoli uno per riga, assumendo implicitamente che non contengano il carattere "a capo".
L'espansione di percorso funziona normalmente, anche in presenza di "a capo", ma potrebbero sorgere problemi sfruttando l'espansione di comando. Per esempio con il comando esterno <code>find</code>, utilizzato per effettuare ricerche in modo ricorsivo, e che di default restituisce i file trovati stampandoli uno per riga, assumendo implicitamente che non contengano il carattere "a capo".


Uno script a titolo esemplificativo:
Uno script a titolo esemplificativo:
Riga 498: Riga 500:
xargs -0 comando [ argomenti ... ]              # li passa come argomenti a un comando esterno
xargs -0 comando [ argomenti ... ]              # li passa come argomenti a un comando esterno
</pre>
</pre>
Si leggano i rispettivi manuali per maggiori informazioni. <code>find</code> ha inoltre la possibilità di eseguire altri comandi esterni sui file trovati direttamente con le opzioni -exec ed -execdir, ma la sintassi è più complessa e non supporta più di un processo per volta, come invece <code>xargs</code>.
Si leggano i rispettivi manuali per maggiori informazioni. <code>find</code> ha la possibilità di eseguire altri comandi esterni sui file trovati direttamente con le opzioni -exec ed -execdir, ma la sintassi è più complessa e non supporta più di un processo per volta, come invece <code>xargs</code>.


== Debug integrato ==
== Debug integrato ==
Riga 509: Riga 511:
* <code>-x</code> stampa ogni comando prima di eseguirlo;
* <code>-x</code> stampa ogni comando prima di eseguirlo;
* <code>-v</code> stampa l'intero blocco di codice che è stato letto (solo la prima volta);
* <code>-v</code> stampa l'intero blocco di codice che è stato letto (solo la prima volta);
* <code>-u</code> interrompe l'esecuzione dello script se si accede a una variabile che non è mai stata assegnata;
* <code>-u</code> interrompe lo script se si accede a una variabile mai assegnata;
* <code>-e</code> interrompe lo script in caso un blocco ritorni un errore (se il valore di ritorno di un comando non è controllato da un <code>if</code>, <code>while</code>, <code>until</code> o dalla concatenazione di comandi con <code>||</code>).
* <code>-e</code> interrompe lo script in caso di errore (se il comando non è controllato da un <code>if</code>, <code>while</code> o dalla concatenazione con <code>||</code>).
Le opzioni possono essere anche accorpate:
$ bash -euvx script.sh


==Link==
==Link==
Link ad altre risorse su '''GNU Bash''':


* [http://www.gnu.org/software/bash/manual/bash.html Bash Referece Manual]: manuale ufficiale
* [http://www.gnu.org/software/bash/manual/bash.html Bash Referece Manual]: manuale ufficiale
Riga 524: Riga 523:
|Verificata_da=
|Verificata_da=
:[[Utente:S3v|S3v]] (in Bash tips)
:[[Utente:S3v|S3v]] (in Bash tips)
:[[Utente:HAL 9000|HAL 9000]] 16:40, 6 lug 2014 (CEST)
:[[Utente:HAL 9000|HAL 9000]] 18:35, 6 lug 2014 (CEST)
|Estesa_da=
|Estesa_da=
:[[Utente:S3v|S3v]] (in Bash tips)
:[[Utente:S3v|S3v]] (in Bash tips)
3 581

contributi