Bash scripting: differenze tra le versioni

aggiunta espansione di parentesi
(aggiunta espansione di parentesi)
Riga 41: Riga 41:
=== Espansione di una variabile ===
=== Espansione di una variabile ===


Con l'unica eccezione dell'assegnazione, quando si accede al contenuto di una variabile senza quotarla, questa può essere trasformata in più di una singola stringa ('''esplosione'''), in base agli spazi contenuti, e perfino in "niente" se è vuota ("niente" proprio come se non presente nel codice). '''Entrambi i comportamenti non sono intuitivi e costituiscono una comune sorgente di errori'''.
Con l'unica eccezione dell'assegnazione, quando si accede al contenuto di una variabile senza quotarla, questa può essere trasformata in più di una singola stringa ('''esplosione'''), in base agli spazi contenuti, e perfino in "niente" se è vuota ("niente" proprio come se non presente nel codice).


Se si vuole sempre considerare il contenuto della variabile come una singola stringa, è necessario accederla quotata (tra virgolette), ossia con <code>"$variabile"</code> oppure <code>"${variabile}"</code>. Si considerino per esempio i seguenti confronti (usati in genere con <code>if</code>, <code>while</code>, ...):
Entrambi i comportamenti non sono intuitivi e costituiscono una comune sorgente di errori. Se si vuole sempre considerare il contenuto della variabile come una singola stringa, è necessario accederla quotata (tra virgolette), ossia con <code>"$variabile"</code> oppure <code>"${variabile}"</code>.
 
Si considerino per esempio i seguenti confronti (usati in genere con <code>if</code>, <code>while</code>, ...):
<pre>
<pre>
[ $var = $var2 ]    # SBAGLIATO! (se una delle due è vuota)
[ $var = $var2 ]    # SBAGLIATO! (se una delle due è vuota)
Riga 173: Riga 175:
</pre>
</pre>


==Caratteri di escape==
==Caratteri di escape, apici e virgolette==


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


Questa sezione non è esaustiva, ma consiglia qualche semplice accorgimento.
Una stringa non racchiusa tra apici 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>. Se non preceduti dal carattere di escape <code>\</code> possono, in base ai caratteri immediatamente successivi, essere espansi. Questa sezione non è esaustiva, ma consiglia qualche semplice accorgimento, in particolare riguardo l'uso di apici e virgolette per ridurre le necessità dell'escape.
 
Inoltre gli spazi (comprendendo tabulazioni e a capo) non quotati vengono compressi:
<pre>
echo parola1  parola2  # stampa parola1 parola2 con un singolo spazio
echo "parola1  parola2" # stampa parola1  parola2 mantenendo gli spazi
</pre>
 
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>
# stampa tutto su una riga con un singolo comando echo
echo "testo su \
più \
righe, tutto stampato \
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)
echo "testo su
più
righe, stampato
su più righe, così com'è scritto"
</pre>


===Racchiudere tra apici===
===Racchiudere tra apici===
Riga 200: Riga 225:
==Espansione di comando==
==Espansione di comando==


Si effettua racchiudendo un comando tra <code>$(</code> e <code>)</code>, oppure tra due apici gravi <code>`</code> (su tastiera con layout italiano: <code>Alt Gr + '</code>). La prima forma è la più leggibile e quella consigliata.
Si effettua racchiudendo un comando tra <code>$(...)</code>, oppure tra due apici gravi <code>`...`</code> (su tastiera con layout italiano: <code>Alt Gr + '</code>):
<pre>$(comando)</pre>
oppure, meno leggibile e sconsigliata:
<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.
Riga 206: Riga 234:
Per esempio:
Per esempio:
<pre>
<pre>
oggi=$(date +%F) # assegna a oggi la data in formato YYYY_MM_DD
oggi=$(date +%F) # assegna alla variabile $oggi la data in formato YYYY_MM_DD


# stampa stati
# stampa stati
Riga 248: Riga 276:
** <code>./*."${estensione}"</code> espande dopo aver espanso la variabile (contrariamente a ~), che può anche essere quotata.
** <code>./*."${estensione}"</code> espande dopo aver espanso la variabile (contrariamente a ~), che può anche essere quotata.


È importante tenere presente per le espansioni di percorso che, se nessun file combacia con un dato pattern, allora l'espansione *non* viene effettuata e i caratteri mantengono il loro valore originale. Per di più <code>*</code> e <code>?</code> sono caratteri validi per un nome di file. L'esistenza di file ottenuti da tali espansioni va pertanto sempre controllata, per esempio con <code>[ -e "$file" ]</code>:
È importante tenere presente per le espansioni di percorso che, se nessun file combacia con un dato pattern, allora l'espansione '''non''' viene effettuata e i caratteri mantengono il loro valore originale. Inoltre <code>*</code> e <code>?</code> sono caratteri validi per un nome di file, e un confronto sull'espansione ottenuta non sarebbe necessariamente risolutivo.
 
L'esistenza di file ottenuti da tali espansioni va pertanto sempre controllata, per esempio con il costrutto <code>[ -e "$file" ]</code>:


<pre>for file in ./*; do
<pre>for file in ./*; do
Riga 263: Riga 293:
{{Suggerimento | L'opzione "--" dopo il comando esterno <code>mv</code> serve per comunicargli che le stringhe che seguono non sono opzioni, nemmeno se iniziassero con il carattere "-". È sempre buona norma utilizzarla come controllo aggiuntivo con comandi che accettano file come argomenti, il cui nome non è noto a priori, in particolare per comandi che manipolano i file come: <code>rm</code>, <code>cp</code>, <code>mv</code>, ecc... <br/>
{{Suggerimento | L'opzione "--" dopo il comando esterno <code>mv</code> serve per comunicargli che le stringhe che seguono non sono opzioni, nemmeno se iniziassero con il carattere "-". È sempre buona norma utilizzarla come controllo aggiuntivo con comandi che accettano file come argomenti, il cui nome non è noto a priori, in particolare per comandi che manipolano i file come: <code>rm</code>, <code>cp</code>, <code>mv</code>, ecc... <br/>
L'opzione deve essere supportata dal comando esterno, non è trattata specialmente dalla shell.}}
L'opzione deve essere supportata dal comando esterno, non è trattata specialmente dalla shell.}}
==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.
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'').
Sintassi della forma iterativa (con indici di un intervallo):
<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..z}</code> dove x, y e z sono tre interi (non possono essere variabili);
* <code>{a..b}</code> dove a e b sono due caratteri (non possono essere variabili);
* <code>{a..b..z}</code> dove a e b sono due caratteri, e z è un intero (non possono essere variabili).
Per esempio:
<pre>
# crea un file temporaneo, associa il percorso a $tmp_file
tmp_file=$(tempfile)
# crea altri dieci file temporanei (.0, .1, .., .9) con lo stesso nome
touch -- "$tmp_file".{0..9}
# operazioni varie con i file
# ...
# pulizia prima di terminare lo script
rm -- "$tmp_file" "$tmp_file".{0..9}
</pre>
Sintassi della forma dichiarativa (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.
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:
<pre>
for file in ./*.{odt,abw,txt,rtf,doc}; do
  if [ -e "$file" ]; then
      ...
  fi
done
</pre>
che è equivalente a:
<pre>
for file in ./*.odt ./*.abw ./*.txt ./*.rtf ./*.doc; do
  if [ -e "$file" ]; then
      ...
  fi
done
</pre>


==Concatenazione e redirezione==
==Concatenazione e redirezione==
Riga 338: Riga 415:
|Verificata_da=
|Verificata_da=
:[[Utente:S3v|S3v]] (versione in Bash tips)
:[[Utente:S3v|S3v]] (versione in Bash tips)
:[[Utente:HAL 9000|HAL 9000]] 18:42, 3 lug 2014 (CEST)
:[[Utente:HAL 9000|HAL 9000]] 14:28, 4 lug 2014 (CEST)
|Estesa_da=
|Estesa_da=
:[[Utente:S3v|S3v]] (versione in Bash tips)
:[[Utente:S3v|S3v]] (versione in Bash tips)
3 581

contributi