Bash scripting: differenze tra le versioni

espansione aritmetica intera
(dotglob e nullglob per espansioni di percorso)
(espansione aritmetica intera)
Riga 207: Riga 207:


===Quotare (tra virgolette)===
===Quotare (tra virgolette)===
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.
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 quelle di variabile/parametro (già viste), di comando e aritmetiche (spiegate in seguito).


Per esempio:
Per esempio:
Riga 215: Riga 215:
echo "\"\" \\"    # è equivalente a '"" \'
echo "\"\" \\"    # è equivalente a '"" \'
echo "$(ls ..)"    # Esegue il comando "ls .." e ne stampa l'output
echo "$(ls ..)"    # Esegue il comando "ls .." e ne stampa l'output
echo "~ * .[a-z]*" # non effettua le espansioni di tilda e percorso, ma stampa letteralmente.
echo "$((2*2))"    # Esegue l'espressione aritmetica e stampa 4
echo "~ * .[a-z]*" # non effettua le espansioni di tilda e percorso, ma stampa letteralmente
echo "{a,b} $'\n'" # stampa letteralmente, senza espansioni
echo "{a,b} $'\n'" # stampa letteralmente, senza espansioni
</pre>
</pre>
Riga 280: Riga 281:
# Attenzione che il carattere aggiunto dev'essere nell'output del comando
# Attenzione che il carattere aggiunto dev'essere nell'output del comando
nr=$(printf "\n")X # SBAGLIATO, $nr contiene solo X
nr=$(printf "\n")X # SBAGLIATO, $nr contiene solo X
</pre>
==Espansione aritmetica intera==
Permette di compiere operazioni aritmetiche tra interi, ritornando sempre una singola stringa contenente l'intero risultante. Può essere quotata, ma non cambia niente.
La sintassi è: <code>$((...))</code><br/>
All'interno delle parentesi è possibile utilizzare:
* le quattro operazioni: <code>+ - * /</code>
* resto/modulo: <code>%</code>
* potenza: <code>**</code>
* variabili da espandere (contenenti valori interi)
* parentesi per cambiare le priorità degli operatori: <code>( )</code>
Esempio:
<pre>
base=9
altezza=5
area=$(($base * $altezza))
echo "Area rettangolo: ${area}"      # Stampa 45
echo "Area triangolo: $(($area / 2))" # Stampa 22 (RICORDA: solo interi)
</pre>
</pre>


Riga 399: Riga 420:
<pre>
<pre>
for file in ./*.odt ./*.abw ./*.txt ./*.rtf ./*.doc; do
for file in ./*.odt ./*.abw ./*.txt ./*.rtf ./*.doc; do
</pre>
==Concatenazione==
; <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)
; <code>&&</code> : operatore logico AND, il secondo comando verrà eseguito solo se il primo avrà esito positivo
Esempio:
<pre>
cd /percorso/dir && comando
</pre>
Attenzione invece alla '''pericolosità''' di:
<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>
; <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):
; <code>{ ... ; }</code> : esegue un blocco di comandi (dopo l'ultimo servono ";" o un "a capo"). È usata nelle funzioni ed è utile per concatenare && e ||:
<pre>
# 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> : esegue il blocco di comandi in una subshell (le variabili vengono ripristinate al loro valore precedente, alla fine del blocco).
===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 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>
comando &&
status=0 || # se corretto
status=$?  # se sbagliato
</pre>
</pre>


==Redirezione==
==Redirezione==
Alcune comuni redirezioni (la lista non è esaustiva):
Alcune comuni redirezioni (la lista non è esaustiva), da scriversi dopo un comando:
* '''> file''' scrive l'output sul file (troncandolo, se esiste);
* '''> file''' dopo un comando ne scrive l'output sul file (troncandolo, se esiste);
* '''>> file''' aggiunge al file (creandolo, se non esiste);
* '''>> file''' aggiunge al file (creandolo, se non esiste);
* '''< file''' legge l'input dal file;
* '''< file''' legge l'input dal file;
Riga 453: Riga 431:
* '''2>&1''' scrive lo standard error sullo standard output;
* '''2>&1''' scrive lo standard error sullo standard output;
* '''&> file''' invia standard output ed error sul file (per aggiungere: '''&>>''');
* '''&> file''' invia standard output ed error sul file (per aggiungere: '''&>>''');
* ''' | ''' : pipe che invia l'output di un comando al successivo come input. I comandi (anche l'ultimo) sono eseguiti in una subshell.
* ''' | ''' : pipe che invia l'output del comando precedente al successivo. Tutti i comandi di una serie di pipe (anche l'ultimo) sono eseguiti in una subshell, e possono stare su righe diverse con la pipe come ultimo carattere.


Esempi:
Esempi:
Riga 510: Riga 488:
</pre>
</pre>
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>.
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>.
==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.
; <code>;</code> : separatore di comandi, con cui un comando verrà eseguito a prescindere dal successo del precedente (in uno script è equivalente a un "a capo" e questa è la concatenazione di default)
; <code>&</code> : separatore che esegue il comando precedente in background (ritorna exit status sempre positivo e non riceve input da tastiera), passando al successivo
; <code>&&</code> : operatore logico AND, che va posizionato tra due comandi, il secondo dei quali è eseguito solo se il primo ha esito positivo
Esempio:
<pre>
cd /percorso/dir && comando
</pre>
Attenzione invece alla '''pericolosità''' di:
<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>
; <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):
; <code>{ ... ; }</code> : esegue un blocco di comandi (dopo l'ultimo servono ";" o un "a capo"). È usata nelle funzioni ed è utile per concatenare && e ||:
<pre>
# 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> : esegue il blocco di comandi in una subshell (le variabili vengono ripristinate al loro valore precedente, alla fine del blocco).
===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 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>
comando &&
status=0 || # se corretto
status=$?  # se sbagliato
</pre>


== Debug integrato ==
== Debug integrato ==
3 581

contributi