Bash scripting - variabili - stringhe: differenze tra le versioni

m
 
(9 versioni intermedie di 2 utenti non mostrate)
Riga 1: Riga 1:
{{Bash_scripting}}
{{Bash scripting}}
=Variabili (stringhe)=
__TOC__
In '''bash''' ogni variabile di default è trattata come una stringa e, benché siano supportati anche interi e array (indicizzati o associativi), questa guida si limita al solo tipo base.
In '''bash''' ogni variabile di default è trattata come una stringa e, benché siano supportati anche interi e array (indicizzati o associativi), questa guida si limita al solo tipo base.


==Nomi di variabili==
== Nomi di variabili ==
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 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.
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.


==Assegnazioni==
== Assegnazioni ==
Non si deve usare il <code>'''$'''</code> davanti alla variabile a cui assegnare.  La forma consigliata, salvo necessità particolari, è quella tra virgolette per le stringhe e le concatenazioni di stringhe e variabili, e senza virgolette per una singola variabile:
Non si deve usare il <code>'''$'''</code> davanti alla variabile a cui assegnare.  La forma consigliata, salvo necessità particolari, è quella tra virgolette per le stringhe e le concatenazioni di stringhe e variabili, e senza virgolette per una singola variabile:
<pre>
<pre>
Riga 29: Riga 29:
</pre>
</pre>


===Modificatori===
=== Modificatori ===
Sono comandi interni che possono essere applicati soltanto a un nome di variabile (senza '''$''') o a un'assegnazione, e in quest'ultimo caso hanno effetto sulla variabile dopo l'avvenuta assegnazione.
Sono comandi interni che possono essere applicati soltanto a un nome di variabile (senza '''$''') o a un'assegnazione, e in quest'ultimo caso hanno effetto sulla variabile dopo l'avvenuta assegnazione.
; export : specifica che la variabile farà parte delle variabili d'ambiente (''environment'') dei comandi esterni eseguiti dallo script:
; export : specifica che la variabile farà parte delle variabili d'ambiente (''environment'') dei comandi esterni eseguiti dallo script:
Riga 50: Riga 50:
VAR="valore"
VAR="valore"
readonly VAR
readonly VAR
# equivalente a:
</pre>
È equivalente a:
<pre>
readonly VAR="valore"
readonly VAR="valore"
VAR="altro valore"  # ERRORE! var ora è una costante
</pre>
</pre>
Per convenzione le costanti sono poste tutte all'inizio dello script, prima anche di eventuali definizioni delle funzioni.
Per convenzione le costanti sono poste tutte all'inizio dello script, prima anche di eventuali definizioni delle funzioni.


===Assegnazione dallo standard input===
=== Assegnazione dallo standard input ===
Con l'istruzione <code>read</code> è possibile assegnare a una o più variabili il contenuto di una riga dello standard input, che senza redirezioni e pipe corrisponde a ciò che viene scritto da tastiera prima di un invio.
Con l'istruzione <code>read</code> è possibile assegnare a una o più variabili il contenuto di una riga dello standard input, che senza redirezioni e pipe corrisponde a ciò che viene scritto da tastiera prima di un invio.


Sintassi (base): <code>read nomevariabile [ ... ]</code>
Sintassi (base):<br/>
:<code>read [ -r ] nomevariabile [ ... ]</code>


Il nome delle variabili non va preceduto da '''$''', proprio come nelle assegnazioni normali. Se sono presenti più nomi di variabile, la riga letta si divide in stringhe delimitate dai caratteri contenuti in <code>$IFS</code> (di default sono tre: spazio, tabulazione e invio), ma all'ultima variabile viene sempre assegnato tutto il contenuto rimanente fino a fine riga.
Il nome delle variabili non va preceduto da '''$''', proprio come nelle assegnazioni normali. Se sono presenti più nomi di variabile, la riga letta si divide in stringhe delimitate dai caratteri contenuti in <code>$IFS</code> (di default sono tre: spazio, tabulazione e invio), ma all'ultima variabile viene sempre assegnato tutto il contenuto rimanente fino a fine riga.
Il carattere <code>\</code> è speciale e può essere utilizzato per inserire in una variabile un carattere contenuto in <code>$IFS</code> e/o andare su più righe (gli "a capo" saranno rimossi però dalla variabile). Per inserirlo è una volta è quindi necessario digitare <code>\\</code>, in alternativa con l'opzione <code>-r</code> si può trattare normalmente.


Esempio:
Esempio:
<pre>
<pre>
printf %s "Scrivi qualcosa e premi invio: "
printf %s "Scrivi qualcosa e premi invio: "
read -r testo
printf %s\\n "Hai scritto: ${testo}"
</pre>
Per permettere tramite <code>\</code> di scrivere più righe, basta rimuovere l'opzione <code>-r</code>:
<pre>
printf %s "Scrivi qualcosa (se vuoi andare a capo, premi prima "\"; mentre per scrivere "\" nel testo scrivi "\\") e premi invio: "
read testo
read testo
printf %s\\n "Hai scritto: ${testo}"
printf %s\\n "Hai scritto: ${testo}" # NOTA: tutto su una riga!
</pre>
 
Se si vogliono modificare i delimitatori, anziché modificare <code>$IFS</code>, che avrebbe effetti anche riguardo la separazione delle stringhe, è necessario assegnarlo sulla stessa riga dell'istruzione, in modo che sia poi ripristinato al suo valore precedente. Anche così facendo l'istruzione <code>read</code> si fermerà comunque al primo "a capo" trovato.
 
Per esempio:
<pre>
printf %s\\n "Scrivi cognome, nome e data di nascita, separati da ',' e premi INVIO."
printf %s "Cognome, Nome, GG/MM/AAAA: "
# $IFS modificata solo per la durata dell'istruzione read
IFS="," read -r cognome nome data  # legge cognome, nome e data, rimuovendo i separatori
                                  # a $nome assegna anche nomi multipli, finché non trova ','
# $IFS ripristinata al suo valore normale
</pre>
</pre>


===Assegnazione con ciclo===
=== Assegnazione con ciclo ===
Con l'istruzione <code>for</code> è possibile eseguire un blocco di istruzioni per ogni elemento di una lista di stringhe, assegnando un elemento per volta a una variabile. Nella sintassi ''POSIX'' è quindi equivalente al ''for each'' di alcuni linguaggi di programmazione.
Con l'istruzione <code>for</code> è possibile eseguire un blocco di istruzioni per ogni elemento di una lista di stringhe, assegnando un elemento per volta a una variabile. Nella sintassi [[POSIX]] è quindi equivalente al ''for each'' di alcuni linguaggi di programmazione.


Sintassi (base):
Sintassi (base):
Riga 106: Riga 129:
Si ricordi che le istruzioni su più righe possono essere scritte sulla stessa, facendo terminare il comando con il carattere speciale <code>;</code> come fatto per esempio con <code>if ... ; then</code>. Per i cicli tuttavia scrivere <code>do</code> su una nuova riga ne migliora la leggibilità.
Si ricordi che le istruzioni su più righe possono essere scritte sulla stessa, facendo terminare il comando con il carattere speciale <code>;</code> come fatto per esempio con <code>if ... ; then</code>. Per i cicli tuttavia scrivere <code>do</code> su una nuova riga ne migliora la leggibilità.


==Espansione di variabile==
== Espansione di variabile ==
I caratteri utilizzati per la divisione di una stringa in più stringhe sono quelli contenuti nella variabile <code>$IFS</code> (di default appunto: spazio, tabulazione e "a capo"), ed è consigliabile non modificarla, se non eventualmente prima di <code>read</code>, per non alterare il normale funzionamento di uno script.
 
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 (e tabulazioni e "a capo") contenuti, e perfino in "niente" se è vuota. "Niente" proprio come se non presente nel codice.
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 (e tabulazioni e "a capo") contenuti, e perfino in "niente" se è vuota. "Niente" proprio come se non presente nel codice.


Riga 138: Riga 163:
Si noti che usando <code>"$ARGUMENTS"</code> (quotata) per una variabile contenente la stringa vuota, il comando leggerebbe lo stesso un argomento e potrebbe fallire.
Si noti che usando <code>"$ARGUMENTS"</code> (quotata) per una variabile contenente la stringa vuota, il comando leggerebbe lo stesso un argomento e potrebbe fallire.


==Variabili speciali==
== Variabili speciali ==
; <code>$?</code> : contiene il valore di uscita dell'ultimo comando o funzione (0 solo in caso di successo);
; <code>$?</code> : contiene il valore di uscita dell'ultimo comando o funzione (0 solo in caso di successo);


Riga 149: Riga 174:
; <code>$@</code> : contiene la lista di tutti i parametri passati allo script corrente o a una funzione. Ogni parametro viene opportunamente quotato, se questa variabile è quotata, e questo ne permette l'utilizzo nei '''cicli for''' per processare (ad esempio) una lista di nomi di file che possono contenere anche spazi. L'uso di questa variabile è quindi in genere preferito rispetto a <code>'''$*'''</code> che ha la stessa funzione ma, se quotata, non quota i vari parametri ma l'intera stringa;
; <code>$@</code> : contiene la lista di tutti i parametri passati allo script corrente o a una funzione. Ogni parametro viene opportunamente quotato, se questa variabile è quotata, e questo ne permette l'utilizzo nei '''cicli for''' per processare (ad esempio) una lista di nomi di file che possono contenere anche spazi. L'uso di questa variabile è quindi in genere preferito rispetto a <code>'''$*'''</code> che ha la stessa funzione ma, se quotata, non quota i vari parametri ma l'intera stringa;


''Esempio:''
Esempio:
<pre>
<pre>
# in "$@" si può anche omettere (lasciando solo: for file) perché implicito
for file in "$@"
for file in "$@"
do
do
     # fare quello che si vuole con "$file"
     # fare quello che si vuole con "$file"
     ...
     ...
done
</pre>
L'istruzione <code>shift</code> può essere usata per rimuovere i parametri più a sinistra (partendo da <code>$1</code>), spostando tutti gli altri (<code>$1</code><-<code>$2</code>, <code>$2</code><-<code>$3</code>, ...), in questo modo si può accedere, come una lista, solo ai successivi.
Per esempio, codice che crea una lista di file in un percorso scelto:
<pre>
# Sintassi accettata: nomescript destinazione lista_file...
# controllo numero argomenti
if [ $# -lt 2 ]; then
    printf %s\\n "Sono richiesti almeno due argomenti!" >&2
    exit 1
fi
# assegno il primo argomento
destinazine=$1
shift  # ora $* e $@ contengono tutti gli altri parametri ($1<-$2, $2<-$3, ...)
      # ossia la lista di file
# controllo l'esistenza della destinazione
if ! [ -d "$destinazione" ]; then
    printf %s\\n "Directory di destinazione non trovata!" >&2
    exit 2
fi
# eseguo un ciclo su tutti i file della lista
# si ricorda che è implicito: in "$@"
for file
do
    # crea il file
    if ! touch -- "${destinazione}/${file}"; then
        # se fallisce si interrompe e stampa un errore
        printf %s\\n "Impossibile creare il file \"${destinazione}/${file}\"!" >&2
        exit 3
    fi
done
done
</pre>
</pre>
Riga 162: Riga 220:
; <code>$!</code> : PID dell'ultimo job in background.
; <code>$!</code> : PID dell'ultimo job in background.


''Esempio:''
Esempio:
<pre>
<pre>
comando &  # lancio un comando in background
comando &  # lancio un comando in background
3 581

contributi