Bash scripting: differenze tra le versioni

aggiunti esempi e casi poco noti, più riformulazione/taglio delle frasi
(aggiunti esempi e casi poco noti, più riformulazione/taglio delle frasi)
Riga 111: Riga 111:
pid=$!    # ottengo il PID del comando
pid=$!    # ottengo il PID del comando
...        # eseguo altre operazioni
...        # eseguo altre operazioni
wait $pid  # riporto il comando in foreground
wait $pid  # attendo la terminazione del comando
status=$?  # catturo il suo exit status
</pre>
</pre>


Riga 189: Riga 190:
Il carattere di escape <code>\</code> prima di un "a capo", anche se quotato (tra virgolette), ha un significato speciale che consente di scrivere un comando su più righe, trattando ogni riga preceduta da <code>\</code> come la continuazione del comando precedente:
Il carattere di escape <code>\</code> prima di un "a capo", anche se quotato (tra virgolette), ha un significato speciale che consente di scrivere un comando su più righe, trattando ogni riga preceduta da <code>\</code> come la continuazione del comando precedente:
<pre>
<pre>
# stampa tutto su una riga con un singolo comando echo
# stampa tutto su una riga
echo "testo su \
echo "testo su \
più \
più \
righe, tutto stampato \
righe"
su una singola riga, come scritto \
tutto di seguito grazie all'uso di \\, \
ma si noti che \\ dev'essere l'ultimo carattere"


# stampa su più righe (sempre con un singolo comando)
# stampa su più righe
echo "testo su
echo "testo su
più
più
righe, stampato
righe"
su più righe, così com'è scritto"
</pre>
</pre>


Riga 332: Riga 329:
==Espansione di parentesi (graffa)==
==Espansione di parentesi (graffa)==


Se i caratteri <code>{</code> e <code>}</code> non sono quotati, e non sono preceduti dal carattere di escape <code>\</code>, in determinate circostanze possono essere espansi.
Se i caratteri <code>{</code> e <code>}</code> non sono quotati, e non sono preceduti dal carattere di escape <code>\</code>, possono essere espansi con due diverse sintassi.


L'espansione supporta due forme: una iterativa, da espandere in un intervallo da un indice a un altro, e una dichiarativa, da espandere nei valori della lista fornita. La prima espansione sostituisce spesso la necessità di ricorrere al comando esterno <code>seq</code>, utilizzato da <code>'''sh'''</code> (''POSIX'').
===Con indici di intervallo===
Sintassi: <code>prefisso{x..y[..z]}suffisso</code>


===Con indici di intervallo===
L'espansione avviene iterativamente per tutte le stringhe a partire da "prefisso'''x'''suffisso" fino a "prefisso'''y'''suffisso", con incrementi di 1 (o '''z''' se specificato). Le stringhe prefisso e suffisso possono essere omesse, e anche essere variabili (anche quotate, purché le graffe non lo siano), mentre x e y (e z, se presente) devono essere determinati valori:
<code>prefisso{x..y[..z]}suffisso</code> espande iterativamente a tutte le stringhe a partire da "prefisso'''x'''suffisso" fino a "prefisso'''y'''suffisso", con incrementi di 1 (o '''z''' se specificato). Le stringhe prefisso e suffisso possono essere omesse, e anche essere variabili (anche quotate, purché le graffe non lo siano), mentre x, y e z devono essere determinati valori:
* <code>{x..y}</code> dove x e y sono due interi (non possono essere variabili);
* <code>{x..y}</code> dove x e y sono due interi (non possono essere variabili);
* <code>{x..y..z}</code> dove x, y e z sono tre interi (non possono essere variabili);
* <code>{x..y..z}</code> dove x, y e z sono tre interi (non possono essere variabili);
Riga 349: Riga 346:
# crea altri dieci file temporanei (.0, .1, .., .9) con lo stesso nome
# crea altri dieci file temporanei (.0, .1, .., .9) con lo stesso nome
touch -- "$tmp_file".{0..9}
touch -- "$tmp_file".{0..9}
# operazioni varie con i file
# ...
# pulizia prima di terminare lo script
rm -- "$tmp_file" "$tmp_file".{0..9}
</pre>
</pre>


===Con lista di stringhe===
===Con lista di stringhe===
<code>prefisso{stringa1,stringa2,...}suffisso</code> espande a tutte le stringhe nella lista, racchiudendole tra il prefisso e il suffisso dati, se presenti. Il prefisso, il suffisso e tutte le stringhe possono essere variabili, anche quotate, purché non siano quotate le graffe e le virgole interne.
Sintassi: <code>prefisso{stringa1,stringa2,...}suffisso</code>
 
L'espansione avviene per tutte le stringhe nella lista, racchiudendole tra il prefisso e il suffisso dati, se presenti. Il prefisso, il suffisso e tutte le stringhe possono essere variabili, anche quotate, purché non siano quotate le graffe e le virgole interne.


Questa espansione è effettuata prima di tutte le altre, e il risultato dell'espansione se non quotato può quindi subire ulteriori espansioni. Per esempio per effettuare un'operazione sui file nella cartella corrente che hanno una data estensione, si può scrivere:
Questa espansione è effettuata prima di tutte le altre, e il risultato dell'espansione se non quotato può quindi subire ulteriori espansioni. Per esempio per effettuare un'operazione sui file nella cartella corrente che hanno una data estensione, si può scrivere:
Riga 367: Riga 361:
done
done
</pre>
</pre>
che è equivalente a:
e la prima riga è equivalente a:
<pre>
<pre>
for file in ./*.odt ./*.abw ./*.txt ./*.rtf ./*.doc; do
for file in ./*.odt ./*.abw ./*.txt ./*.rtf ./*.doc; do
  if [ -e "$file" ]; then
      ...
  fi
done
</pre>
</pre>


Riga 406: Riga 396:


* [http://www.tldp.org/LDP/abs/html/special-chars.html Advanced Bash-Scripting Guide: Special Characters]
* [http://www.tldp.org/LDP/abs/html/special-chars.html Advanced Bash-Scripting Guide: Special Characters]


Dirige output di comando su file:
Dirige output di comando su file:
Riga 422: Riga 411:
Cancella contenuto di un file:
Cancella contenuto di un file:
  $ :> xterm.txt
  $ :> xterm.txt
===Catturare l'exit status===
L'exit status è il valore di uscita di un comando. È tipicamente di zero in caso di successo, e un valore maggiore (fino a 255) in presenza di errori.
Per catturare l'exit status 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>):
<pre>
comando &&
status=0 || # se corretto
status=$?  # se sbagliato
</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 436: Riga 444:


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".
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".
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".


Uno script a titolo esemplificativo:
Uno script a titolo esemplificativo:
Riga 464: Riga 474:
<pre>
<pre>
find /percorso -opzione1 ... -opzioneN -print0 | # trova file che soddisfano le condizioni date
find /percorso -opzione1 ... -opzioneN -print0 | # trova file che soddisfano le condizioni date
xargs -0 comando [ argomenti ... ]              # passa questi file al comando
xargs -0 comando [ argomenti ... ]              # li passa come argomenti a un comando esterno
</pre>
</pre>
Si leggano i rispettivi manuali per maggiori informazioni (<code>man find</code> e <code>man xargs</code>).
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>.


== Debug integrato ==
== Debug integrato ==
Riga 472: Riga 482:
'''Bash''', proprio come '''dash''', ha delle opzioni che ne consentono il debug.
'''Bash''', proprio come '''dash''', ha delle opzioni che ne consentono il debug.


Per iniziare invocando uno script con <code>-n</code> è possibile effettuare un primitivo controllo di sintassi. Si noti che possibili comandi inesistenti non vengono controllati e nemmeno le espansioni (di variabili, percorsi, ecc...), ma può essere utile per verificare che tutti i blocchi sono stati chiusi correttamente prima di eseguire lo script:
Invocando uno script con <code>-n</code> è possibile effettuare un primitivo controllo di sintassi. Non vengono controllati comandi inesistenti e nemmeno le espansioni, ma può essere utile per verificare che i blocchi sono stati chiusi correttamente prima di eseguire lo script:
  $ bash -n script.sh
  $ bash -n script.sh


Dopo questo primo controllo ci sono altre opzioni utili, che possono essere impiegate anche congiuntamente nell'esecuzione dello script:
Altre opzioni utili, che possono essere impiegate anche congiuntamente durante l'esecuzione:
* <code>-x</code> invia sull'output per gli errori ogni comando prima di eseguirlo, preceduto da un prompt "+ ";
* <code>-x</code> stampa ogni comando prima di eseguirlo;
* <code>-v</code> invia sull'output per gli errori 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, può essere utile in caso di errori di battitura;
* <code>-u</code> interrompe l'esecuzione dello script se si accede a una variabile che non è mai stata assegnata;
* <code>-e</code> interrompe lo script in caso un comando ritorni un errore, se il suo valore di ritorno 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 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>).
Le opzioni possono essere anche accorpate:
Le opzioni possono essere anche accorpate:
  $ bash -evx script.sh
  $ bash -euvx script.sh
 
L'opzione <code>-e</code> può essere utilizzata anche fuori dal debug, ma è consigliabile non fare affidamento sulla sua presenza nella prima riga dello script (<code>#! /bin/bash -e</code>), visto che può essere ignorata semplicemente invocando la shell con lo script come argomento oppure importando il contenuto dello script. I valori di ritorno di ogni comando che può fallire vanno invece controllati nel codice.


==Link==
==Link==
Riga 495: Riga 503:
|Verificata_da=
|Verificata_da=
:[[Utente:S3v|S3v]] (versione in Bash tips)
:[[Utente:S3v|S3v]] (versione in Bash tips)
:[[Utente:HAL 9000|HAL 9000]] 21:46, 4 lug 2014 (CEST)
:[[Utente:HAL 9000|HAL 9000]] 11:11, 5 lug 2014 (CEST)
|Estesa_da=
|Estesa_da=
:[[Utente:S3v|S3v]] (versione in Bash tips)
:[[Utente:S3v|S3v]] (versione in Bash tips)
3 581

contributi