Bash scripting: differenze tra le versioni

correzioni, riordinamento, aggiunte priorità delle espansioni
(espansione aritmetica intera)
(correzioni, riordinamento, aggiunte priorità delle espansioni)
Riga 1: Riga 1:
{{Versioni_compatibili}}
{{Versioni_compatibili}}
==Introduzione==
==Introduzione==
Questa non è una guida completa, per la vastità dell'argomento, ma cercherà di far luce sui comportamenti più distintivi di Bash, partendo dai più facili da sbagliare.
Questa non è una guida completa, per la vastità dell'argomento, ma cercherà di far luce sui comportamenti più distintivi di Bash, con enfasi particolare sulle espansioni di stringhe.


Per l'uso interattivo si rimanda a [[Bash tips]].
Per l'uso interattivo si rimanda a [[Bash tips]].
Riga 42: Riga 42:
Ciò è ancora più importante quando si passa la variabile a un comando che agisce su un file indicato dalla variabile, il cui contenuto in presenza di spazi (comuni per i nomi di file degli utenti) potrebbe venir trattato come una lista di file.
Ciò è ancora più importante quando si passa la variabile a un comando che agisce su un file indicato dalla variabile, il cui contenuto in presenza di spazi (comuni per i nomi di file degli utenti) potrebbe venir trattato come una lista di file.


Esempio di codice che crea un backup di un file indicato da una variabile, se il suo nome non termina già con estensione .bak. Si notino le virgolette attorno alla variabili, omesse solo nelle assegnazioni (senza spazi), per garantire che ogni variabile venga espansa in un solo argomento:
Esempio di codice che crea un backup di un file indicato da una variabile:
<pre>
<pre>
if [ "$file" = "${file%.bak}" ]; then
cp -- "$file" "${file}.bak"
  oldfile=$file
  file=${file}.bak
  cp -- "$oldfile" "$file"
fi
</pre>
</pre>


Riga 91: Riga 87:
wait $pid  # attendo la terminazione del comando
wait $pid  # attendo la terminazione del comando
status=$?  # catturo il suo exit status
status=$?  # catturo il suo exit status
</pre>
== Manipolazione delle stringhe ==
Nelle shell *nix, storicamente, la manipolazione delle stringhe viene fatto attraverso programmi esterni alla shell come sed, awk e perl. Questi programmi vengono ancora usati quando si vuole mantenere la compatibilità con la shell <code>'''sh'''</code> (''POSIX''), tuttavia imparare anche il solo sed (il più semplice dei tre) non è cosa immediata.
Se si usa Bash non è necessario usare nessun programma esterno, ma basta imparare i tre operatori fondamentali ed alcuni concetti di base, per poter fare tutte le manipolazioni più comuni direttamente sulle variabili.
Si assegna una stringa a una variabile e accedendola tramite la forma con le graffe, si può ricorrere a un modificatore che manipola la stringa (senza modificare il contenuto della variabile), ad esempio:
VAR="stringa-di-esempio"
echo "${VAR#stringa-}"
ritorna il contenuto della variable VAR senza il prefisso "stringa-". VAR non viene modificata, salvo una nuova assegnazione:
VAR=${VAR#stringa-}
ora il prefisso "stringa-" è stato eliminato anche dalla variabile VAR.
I modificatori sono molti, ma possono essere facilmente ricordati se si imparano i tre fondamentali:
; <code>#</code> : sottrae dall'inizio della stringa ''(minimale)''
; <code>%</code> : sottrae dalla fine della stringa ''(minimale)''
; <code>/</code> : sostituisce una sottostringa con un'altra ''(solo la prima volta che viene incontrata)''
Questi operatori sono minimali, questo vuol dire che se si usano le espressioni regolari per indicare la sottostringa (da eliminare o sostituire) verrà individuata in caso di ambiguità la sottostringa più piccola (o solo la prima nel caso della sostituzione).
Per ottenere gli operatori massimali basta raddoppiare il simbolo:
; <code>##</code> : sottrae dall'inizio della stringa ''(massimale)''
; <code>%%</code> : sottrae dalla fine della stringa ''(massimale)''
; <code>//</code> : sostituisce una sottostringa con un'altra ''(tutte le volte che viene incontrata)''
Gli operatori massimali cercano di individuare la sottostringa più grande che corrisponde all'espressione regolare (nel caso del modificatore '''//''' tutte le sottostringhe vengono sostituite).
Per una spiegazione dettagliata di tutti i modificatori e anche di altri modi di manipolare le stringhe in Bash (ad esempio <code>expr</code>) vedere:
* [http://www.tldp.org/LDP/abs/html/string-manipulation.html Advanced Bash-Scripting Guide: Manipulating Strings]
=== Esempi: manipolazione delle stringhe ===
<pre>
VAR="questa.sarebbe.una.stringa.di.esempio"
 
                    # Risultato:
 
echo "${VAR#*.}"    # --> sarebbe.una.stringa.di.esempio
echo "${VAR##*.}"    # --> esempio
 
echo "${VAR%.*}"    # --> questa.sarebbe.una.stringa.di
echo "${VAR%%.*}"    # --> questa
 
echo "${VAR/st/ST}"  # --> queSTa.sarebbe.una.stringa.di.esempio
echo "${VAR//st/ST}" # --> queSTa.sarebbe.una.STringa.di.esempio
</pre>
===Esempio: alternativa a basename===
Quando in uno script ci si deve riferire al nome dello script stesso, è usuale utilizzare il comando esterno <code>'''basename'''</code>. Tuttavia, tramite i modificatori del paragrafo precedente, Bash stessa è in grado di fornire questa funzionalità con l'espressione <code>${0##*/}</code>:
<pre>
readonly BASENAME=${0##*/} # associa il basename a una costante
usage () {
  echo "Usage: ${BASENAME}"
}
</pre>
</pre>


Riga 207: Riga 141:


===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 quelle di variabile/parametro (già viste), di comando e aritmetiche (spiegate in seguito).
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 attivate da <code>$</code>, ossia di variabile/parametro, di comando e aritmetiche.


Per esempio:
Per esempio:
Riga 218: Riga 152:
echo "~ * .[a-z]*" # non effettua le espansioni di tilda e percorso, ma stampa letteralmente
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>
Le espansione attivate da <code>$</code> avvengono con la stessa priorità, e in una stringa quotata sono le uniche permesse, quindi il risultato di un'espansione non può essere espanso una seconda volta all'interno di una stringa quotata.
==Espansione di parametro (stringa)==
È una forma modificata dell'espansione di variabile, che permette di operare sulla stringa contenuta con un modificatore.
L'espansione di parametro è utilizzabile ogni volta che lo è quella di variabile, con un'unica differenza: l'espansione di variabile ha priorità maggiore, il che permette di inserire una stringa ottenuta dall'espansione di una variabile in un'espansione di parametro, mentre non è possibile annidare più espansioni di parametro.
Modificatori:
* <code>${#var}</code> ritorna il numero di caratteri della stringa contenuta in $var;
* <code>${!var}</code> ritorna il contenuto della variabile, il cui nome è contenuto in $var (accesso indiretto);
* espande o assegna valori di default/alternativi;
* manipolatori di stringa (rimozione e sostituzione);
* trasformazione in uppercase / lowercase.
===Manipolazione delle stringhe===
Nelle shell *nix, storicamente, la manipolazione delle stringhe viene fatto attraverso programmi esterni alla shell come sed, awk e perl. Questi programmi vengono ancora usati quando si vuole mantenere la compatibilità con la shell <code>'''sh'''</code> (''POSIX'') o per manipolazioni molto complesse.
Se si usa Bash non è necessario usare nessun programma esterno, ma basta imparare i tre operatori fondamentali ed alcuni concetti di base, per poter fare tutte le manipolazioni più comuni direttamente sulle variabili.
Si assegna una stringa a una variabile e accedendola tramite la forma con le graffe, si può ricorrere a un modificatore che manipola la stringa (senza modificare il contenuto della variabile), ad esempio:
<pre>
VAR="stringa-di-esempio"
echo "${VAR#stringa-}"
</pre>
ritorna il contenuto della variable VAR senza il prefisso "stringa-". VAR non viene modificata, salvo una nuova assegnazione:
<pre>
VAR=${VAR#stringa-}
</pre>
ora il prefisso "stringa-" è stato eliminato anche dalla variabile VAR.
I modificatori sono molti, ma possono essere facilmente ricordati se si imparano i tre fondamentali:
* <code>#</code> sottrae dall'inizio della stringa ''(minimale)'';
* <code>%</code> sottrae dalla fine della stringa ''(minimale)'';
* <code>/</code> sostituisce una sottostringa con un'altra ''(solo la prima volta che viene incontrata)''.
Questi operatori sono minimali, questo vuol dire che se si usano le espressioni regolari per indicare la sottostringa (da eliminare o sostituire) verrà individuata in caso di ambiguità la sottostringa più piccola (o solo la prima nel caso della sostituzione).
Per ottenere gli operatori massimali basta raddoppiare il simbolo:
* <code>##</code> sottrae dall'inizio della stringa ''(massimale)'';
* <code>%%</code> sottrae dalla fine della stringa ''(massimale)'';
* <code>//</code> sostituisce una sottostringa con un'altra ''(tutte le volte che viene incontrata)''.
Gli operatori massimali cercano di individuare la sottostringa più grande che corrisponde all'espressione regolare (nel caso del modificatore '''//''' tutte le sottostringhe vengono sostituite).
Si noti che le stringhe interne a un'espansione di parametro possono essere delle variabili, ma non altre espansioni di parametro:
<pre>
# cambia l'estensione nella variabile file
if [ "$file" != "${file%${estensione}}" ]; then
  file=${file%${estensione}}${nuova_estensione}
fi
</pre>
Per una spiegazione dettagliata di tutti i modificatori e anche di altri modi di manipolare le stringhe in Bash (ad esempio <code>expr</code>) vedere:
* [http://www.tldp.org/LDP/abs/html/string-manipulation.html Advanced Bash-Scripting Guide: Manipulating Strings]
====Esempi: manipolazione delle stringhe====
<pre>
VAR="questa.sarebbe.una.stringa.di.esempio"
 
                    # Risultato:
 
echo "${VAR#*.}"    # --> sarebbe.una.stringa.di.esempio
echo "${VAR##*.}"    # --> esempio
 
echo "${VAR%.*}"    # --> questa.sarebbe.una.stringa.di
echo "${VAR%%.*}"    # --> questa
 
echo "${VAR/st/ST}"  # --> queSTa.sarebbe.una.stringa.di.esempio
echo "${VAR//st/ST}" # --> queSTa.sarebbe.una.STringa.di.esempio
</pre>
====Esempio: alternativa a basename====
Quando in uno script ci si deve riferire al nome dello script stesso, è usuale utilizzare il comando esterno <code>'''basename'''</code>. Una possibile alternativa:
<pre>
usage () {
  echo "Usage: ${0##*/}"
}
</pre>
</pre>


==Espansione di comando==
==Espansione di comando==
Consiste nel trasformare l'output di un comando qualsiasi (interno della shell, esterno, una funzione e anche forme composte) in argomenti per un altro comando, oppure nel valore da assegnare a una variabile. Si effettua racchiudendo un comando tra <code>$(...)</code>, oppure tra due apici gravi <code>`...`</code> (su tastiera con layout italiano: <code>Alt Gr + '</code>):
Consiste nel trasformare l'output di un comando qualsiasi (interno della shell, esterno, una funzione e anche forme composte) in argomenti per un altro comando, oppure nel valore da assegnare a una variabile. Si effettua racchiudendo un comando tra <code>$(...)</code>:
<pre>$(comando)</pre>
<pre>$(comando)</pre>
oppure, meno leggibile e sconsigliata:
oppure, meno leggibile e sconsigliata tra <code>`...`</code> (su tastiera con layout italiano: <code>Alt Gr + '</code>):
<pre>`comando`</pre>  
<pre>`comando`</pre>  
Inoltre la prima forma può essere annidata facilmente, mentre la seconda richiederebbe un livello aggiuntivo di escape.


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 305: Riga 320:
==Espansione di tilda==
==Espansione di tilda==
Sintassi:
Sintassi:
* <code>~</code> (tilda) si espande alla home;
* <code>~</code> si espande alla home, se non è quotata (equivalente all'uso di $HOME, che può essere quotata);
* <code>~utente</code> si espande alla home di un dato utente, se esiste, ma la stringa non può essere quotata né essere una variabile.
* <code>~utente</code> si espande alla home di un dato utente, se esiste, ma la stringa non può essere quotata né essere una variabile.
Si distingue dall'espansione di percorso perché:
* può essere espansa in un'assegnazione, se non è quotata;
* ha priorità maggiore dell'espansione di parametro/variabile; per cui, se assegnata quotata a una variabile, non sarà espansa quando si accede alla variabile.


Esempi:
Esempi:
<pre>
<pre>
var=~             # assegno ~ alla variabile
var=~       # assegno la home dell'utente a $var
echo "$var"      # stampa letteralmente ~
var=$HOME    # equivalente (ma più chiaro)
echo $var        # equivalente a sopra, nessuna espansione
var="~"      # assegno ~ a $var
var=$(echo ~)    # assegno a var la home dell'utente
echo "$var"  # stampo ~
var=$HOME        # equivalente
echo $var    # equivalente (nessuna espansione)
var=$(echo ~root) # assegno a var la home di root
var=~root   # assegno a var la home di root
echo ~           # stampo la home dell'utente
echo ~       # stampo la home dell'utente
echo "~"         # stampo ~
echo "$HOME" # equivalente
echo ~root       # stampo la home di root
echo "~"     # stampo ~
echo ~fdsfd       # stampo ~fdsfd (l'utente fdsfd non esiste)
echo ~root   # stampo la home di root
echo ~fdsfd # stampo ~fdsfd (l'utente fdsfd non esiste)
</pre>
</pre>


Riga 325: Riga 345:
{{Box | File | Su UNIX e Unix-like per file si può intendere sia un file regolare, ma anche una directory, un link simbolico, una pipe, un socket, un device, ecc...}}
{{Box | File | Su UNIX e Unix-like per file si può intendere sia un file regolare, ma anche una directory, un link simbolico, una pipe, un socket, un device, ecc...}}


Non racchiudere tra virgolette e apici permette le espansioni di percorso. È sempre consigliabile racchiudere tutto il resto tra virgolette, per non permettere espansioni accidentali.
Le espansioni di percorso sono possibili solo se i caratteri speciali che la consentono non sono racchiusi tra virgolette, apici o preceduti da <code>/<code>. È sempre consigliabile racchiudere tutto il resto tra virgolette, per non permettere espansioni accidentali.


Infatti si noti che l'espansione, contrariamente a quella di tilda, può avvenire anche in base al contenuto di una variabile, se non è quotata:
L'espansione non è possibile, direttamente, in un'assegnazione. Avendo la priorità più bassa, contrariamente all'espansione di tilda può avvenire anche in seguito all'espansione di una variabile (e con ogni altra espansione), se non è quotata:
<pre>
<pre>
var=*       # assegno * a $var
var="./*# assegno ./* a $var
var="*"     # come sopra
var=./*    # come sopra (nessuna espansione in un'assegnazione)
echo "$var" # stampa letteralmente *
echo "$var" # stampa letteralmente ./*
echo $var  # stampa la lista di tutti i file non nascosti
echo $var  # stampa la lista di tutti i file non nascosti
             # nella directory corrente, oppure * se è vuota
             # nella directory corrente, oppure ./* se è vuota
</pre>
</pre>


Riga 348: Riga 368:
* <code>"./${nome}"*</code>espande a tutti i file inizianti con $nome;
* <code>"./${nome}"*</code>espande a tutti i file inizianti con $nome;
* <code>./*/</code> espande a tutte le directory non nascoste;
* <code>./*/</code> espande a tutte le directory non nascoste;
* <code>./.*</code> espande a tutti i file nascosti (comprese "'''.'''" e "'''..'''", ossia directory corrente e superiore).
* <code>./.*</code> espande a tutti i file nascosti ('''ATTENZIONE:''' comprese "'''.'''" e "'''..'''", ossia directory corrente e superiore).


È importante sapere che, se nessun file combacia con un dato pattern, allora l'espansione '''non''' viene effettuata e i caratteri mantengono il loro valore letterale. E inoltre <code>*</code> e <code>?</code> sono caratteri validi per un nome di file.
È importante sapere che, se nessun file combacia con un dato pattern, allora l'espansione '''non''' viene effettuata e i caratteri mantengono il loro valore letterale. E inoltre <code>*</code> e <code>?</code> sono caratteri validi per un nome di file.
Riga 385: Riga 405:


==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>, possono essere espansi con due diverse sintassi.
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 per generare una lista di stringhe. E più espansioni di parentesi possono essere annidate.
 
Questa espansione avviene prima di tutte le altre, e il risultato può passare per tutte le altre espansioni. Non può avvenire in un'assegnazione, se non all'interno di altre espansioni.


===Con indici di intervallo===
===Con indici di intervallo===
Riga 555: Riga 577:
|Verificata_da=
|Verificata_da=
:[[Utente:S3v|S3v]] (in Bash tips)
:[[Utente:S3v|S3v]] (in Bash tips)
:[[Utente:HAL 9000|HAL 9000]] 19:58, 9 lug 2014 (CEST)
:[[Utente:HAL 9000|HAL 9000]] 12:05, 12 lug 2014 (CEST)
|Estesa_da=
|Estesa_da=
:[[Utente:S3v|S3v]] (in Bash tips)
:[[Utente:S3v|S3v]] (in Bash tips)
3 581

contributi