[inizio] [indice generale] [precedente] [successivo] [indice analitico] [contributi]


45. Bash: parametri, variabili, espansione e sostituzione

Un compito molto importante delle shell Unix è quello di rimpiazzare variabili e simboli speciali con quello che rappresentano. A fianco di questo problema si pone la necessità di proteggere ciò che si vuole evitare sia espanso dalla shell. Anche questi simboli che proteggono contro l'espansione sono soggetti a loro volta a un procedimento di sostituzione: quando la shell ha terminato l'interpretazione di un'istruzione, questi devono essere rimossi in modo da non lasciarne traccia per un eventuale programma che dovesse ricevere questi dati in forma di argomenti.

45.1 Quoting: protezione

Il quoting è un'azione con la quale si toglie il significato speciale che può avere qualcosa per la shell. Si distinguono tre possibilità: il carattere di escape (rappresentato dalla barra obliqua inversa), gli apici semplici e gli apici doppi (o virgolette). In generale, il concetto può essere trasferito in quello della protezione da un'interpretazione errata di ciò che si intende veramente.

È importante notare che il concetto di «protezione» è utilizzato in molte situazioni estranee all'uso della shell, e ogni contesto può avere una logica differente.

45.1.1 Escape e continuazione

La barra obliqua inversa (`\') rappresenta il carattere di escape. Serve per preservare il significato letterale del carattere successivo, cioè evitare che venga interpretato diversamente da quello che è veramente.

Un caso particolare si ha quando il simbolo `\' è esattamente l'ultimo carattere della riga, o meglio, quando questo è seguito immediatamente dal codice di interruzione di riga: rappresenta una continuazione nella riga successiva. *1*

Il simbolo `\', utilizzato per interrompere un'istruzione e riprenderla nella riga successiva, può essere utilizzato sia con una shell interattiva che all'interno di uno script. Bisogna fare bene attenzione a non lasciare spazi dopo questo simbolo, altrimenti non si comporta più come segno di continuazione.

Esempi

ls -l \*

Tenta di visualizzare le caratteristiche del file il cui nome corrisponde a un asterisco (`*'). Se non venisse usata la barra obliqua inversa che funge da escape, l'asterisco verrebbe trasformato nell'elenco dei nomi dei file contenuti nella directory corrente.

#!/bin/bash
echo "Saluti e baci \
paga la multa e taci"

Nello script precedente, il comando `echo' è stato spezzato a metà in modo da poter proseguire nella riga successiva.

45.1.2 Apici singoli

Racchiudendo una serie di caratteri tra una coppia di apici semplici (`'') si mantiene il valore letterale di questi caratteri. Evidentemente, un apice singolo non può essere contenuto in una stringa del genere.

L'apice inclinato nel modo opposto (``') viene usato con un altro significato che non rientra in quello della protezione delle stringhe delimitate.

Esempi

echo 'Attenzione: $0 $1 \ ... restano "inalterati".'[Invio]

Attenzione: $0 $1 \ ... restano "inalterati".

45.1.3 Apici doppi

Racchiudendo una serie di caratteri tra una coppia di apici doppi si mantiene il valore letterale di questi caratteri, a eccezione di `$', ``' e `\'. I simboli `$' e ``' (dollaro e apice inverso) mantengono il loro significato speciale all'interno di una stringa racchiusa tra apici doppi, mentre la barra obliqua inversa (`\') si comporta come carattere di escape solo quando è seguita da `$', ``', `"' e `\'; quando si trova al termine della riga serve come indicatore di continuazione nella riga successiva.

Si tratta di una particolarità molto importante, attraverso la quale è possibile definire delle stringhe in cui si possono inserire:

Esempi

echo "Il parametro \$0 contiene: \"$0\""[Invio]

Il parametro $0 contiene: "-bash"

45.2 Parametri e variabili

Nella documentazione originale di Bash si utilizza il termine «parametro» per identificare diversi tipi di entità:

In questo documento, per evitare confusioni, si riserva il termine parametro solo ai primi due tipi di entità.

L'elemento comune tra i parametri e le variabili è il modo con cui questi devono essere identificati quando si vuole leggere il loro contenuto: occorre il simbolo `$' davanti al nome (o al simbolo) dell'entità in questione, mentre per assegnare un valore all'entità (sempre che ciò sia possibile), questo prefisso non deve essere indicato.

45.2.1 Parametri

Il termine parametro viene utilizzato qui per definire una variabile speciale che può essere solo letta, e rappresenta alcuni elementi particolari dell'attività della shell. Come nel caso delle variabili, per fare riferimento al contenuto di un parametro occorre utilizzare il prefisso `$' che di per sé non è parte del nome del parametro. Tuttavia, per maggiore chiarezza espressiva, dal momento che non è possibile assegnare un valore a queste entità, quando nelle documentazioni si fa riferimento a un parametro, si utilizza quasi sempre il suo nome (o il simbolo che rappresenta) preceduto dal simbolo `$'.

Quindi, dire che il primo parametro posizionale si chiama `$1' non è esatto: è semplicemente `1', solo che per leggerne il contenuto si deve aggiungere `$' davanti e non esiste la possibilità di trattare questo `1' come una variabile di shell. Inoltre, parlare del parametro `1', può essere fonte di confusione.

Un parametro è definito, cioè esiste, quando contiene un valore, compresa la stringa vuota.

45.2.1.1 Parametri posizionali

Un parametro posizionale è definito da una o più cifre numeriche a eccezione del parametro `$0' che ha invece un significato speciale. I parametri posizionali rappresentano gli argomenti forniti al comando: `$1' è il primo, `$2' è il secondo, e così di seguito.

Quando viene eseguita una funzione, questi parametri vengono rimpiazzati temporaneamente con gli argomenti forniti alla funzione.

Quando si utilizza un parametro composto da più di una cifra numerica, occorre racchiudere questo numero tra parentesi graffe: `${10}', `${11}',...

45.2.1.2 Parametri speciali

I parametri speciali sono rappresentati da uno zero o un altro simbolo speciale.

45.2.2 Variabili di shell

Una variabile è definita quando contiene un valore, compresa la stringa vuota. L'assegnamento di un valore si ottiene con una dichiarazione del tipo seguente:

<nome-di-variabile>=[<valore>]

Il nome di una variabile può contenere lettere, cifre numeriche e il segno di sottolineatura, ma il primo carattere non può essere un numero.

Se non viene fornito il valore da assegnare, si intende la stringa vuota. La lettura del contenuto di una variabile si ottiene facendone precedere il nome dal simbolo `$'.

La tabella 45.1 mostra l'elenco delle variabili il cui valore viene assegnato direttamente dalla shell.

Variabile Descrizione
sh OPTIND L'indice del prossimo argomento da elaborare dal comando `getopts'.
" OPTARG Il valore dell'ultimo argomento elaborato da `getopts'.
ksh RANDOM Un numero intero casuale.
" REPLY La destinazione predefinita per il comando interno `read'.
" SECONDS Il numero di secondi trascorsi dall'avvio della shell.
" PWD La directory corrente.
" OLDPWD La directory corrente visitata precedentemente.
" LINENO Il numero della riga dello script o della funzione.
bash HISTCMD L'indice nel registro storico dei comandi.
" UID Lo UID dell'utente.
" EUID Lo UID efficace dell'utente.
" GROUPS Un array contenente i numeri GID di cui l'utente è membro.
" HOSTTYPE Il nome del tipo di elaboratore.
" OSTYPE Il nome del sistema operativo.
" MACHTYPE Architettura e sistema operativo utilizzato.
" BASH_VERSION Il numero di versione di Bash.
" BASH Il percorso assoluto della copia corrente dell'eseguibile `bash'.
" PPID Il PID del processo genitore della shell attuale.
" SHLVL Il livello di annidamento dell'eseguibile `bash'.

Tabella 45.1: Elenco delle variabili più importanti della shell Bash, il cui valore viene assegnato direttamente dalla shell stessa. L'elenco è classificato in base all'origine storica.

In particolare, è possibile assegnare un valore alla variabile `SECONDS' ottenendo il riavvio del conteggio dei secondi a partire da quel valore.

La tabella 45.2 mostra l'elenco di alcune delle altre variabili utilizzate dalla shell.

Variabile Descrizione Predefinito
sh IFS Internal Field Separator. <SP><HT><LF>
" PATH I percorsi di ricerca per i comandi.
" HOME La directory personale dell'utente.
" CDPATH Il percorso di ricerca per il comando `cd'.
" MAILPATH La directory dei file della posta elettronica.
" PS1 L'invito primario. «bash$ »
" PS2 L'invito secondario. «>»
csh IGNOREEOF Il numero di EOF necessari per terminare. 1
ksh PS3 l'invito del comando `select'.
" PS4 «+ »
" TMOUT Tempo di attesa massima (secondi).
bash HISTSIZE Comandi da conservare nello storico. 500
" HISTFILE File storico dei comandi inseriti. «~/.bash_history»
" ENV Il nome di un file di configurazione POSIX.
" BASH_ENV File di configurazione per l'esecuzione di script.

Tabella 45.2: Elenco di alcune delle altre variabili utilizzate dalla shell Bash. L'elenco è classificato in base all'origine storica.

In particolare vanno prese in considerazioni le variabili descritte di seguito.

45.2.2.1 Esportazione

Quando si creano o si assegnano delle variabili, queste hanno una validità limitata all'ambito della shell stessa, per cui, i comandi interni sono al corrente di queste variazioni mentre i programmi che vengono avviati non ne risentono. Perché anche i programmi ricevano le variazioni fatte sulle variabili, queste devono essere esportate. L'esportazione delle variabili si ottiene con il comando interno `export'.

Esempi

PIPPO="ciao"

export PIPPO

Crea la variabile `PIPPO' e quindi la esporta.

export PIPPO="ciao"

Esegue la stessa operazione dell'esempio precedente, ma in un colpo solo.

45.3 Espansione

Con questo termine si intende la traduzione di parametri, variabili e altre entità analoghe, nel loro risultato finale. L'espansione, intesa in questi termini, viene eseguita sulla riga di comando, dopo che questa è stata scomposta in parole. Esistono sette tipi di espansione eseguiti nell'ordine seguente:

  1. parentesi graffe;

  2. tilde;

  3. parametri e variabili;

  4. comandi;

  5. aritmetica (da sinistra a destra);

  6. suddivisione delle parole;

  7. percorso o pathname.

Nei sistemi che possono gestirlo esiste un tipo addizionale: si tratta della sostituzione di processo e qui non viene descritta.

Solo l'espansione attraverso parentesi graffe, la suddivisione in parole e l'espansione di percorso, possono cambiare il numero delle parole di un'espressione. Gli altri tipi di espansione trasformano una parola in un'altra parola con l'unica eccezione del parametro `$@' che invece si espande in più parole.

Dopo tutte le fasi di espansione e sostituzione, tutti i simboli utilizzati per la protezione vengono eliminati.

45.3.1 Parola

Il termine parola ha un significato particolare nella terminologia utilizzata per la shell: si tratta di una sequenza di caratteri che rappresenta qualcosa di diverso da un operatore. In altri termini, si può definire come una stringa che viene presa così com'è e rappresenta una cosa sola. Per esempio, un argomento fornito a un programma è una parola.

L'operazione di suddivisione in parole riguarda il meccanismo con cui una stringa viene analizzata e suddivida in parole in base a un criterio determinato. Questo problema viene ripreso più avanti.

45.3.2 Espansione delle parentesi graffe

L'espansione delle parentesi graffe deriva dalla shell C.

<prefisso>{<elenco>}<suffisso>

L'elenco indicato all'interno delle parentesi graffe è fatto di elementi separati da virgola. Il risultato è una serie di parole composte tutte dal prefisso e dal suffisso indicati e all'interno uno degli elementi della lista. Per esempio, `a{b,c,d}e' genera esattamente le tre parole `abe ace ade'.

Esempi

mkdir /usr/local/src/pippo/{vecchio,nuovo,dist,bachi}

Crea quattro directory: `vecchio/', `nuovo/', `dist/' e `bachi/' a partire da `/usr/local/src/pippo/'.

chown root /usr/{paperino/{qui,quo,qua},topolino/{t??.*,minnie}}

cambia proprietà di una serie di file:

/usr/paperino/qui
/usr/paperino/quo
/usr/paperino/qua
/usr/topolino/t??.*
/usr/topolino/minnie

e chiaramente, `/usr/topolino/t??.*' viene ulteriormente espanso.

45.3.3 Espansione della tilde

L'espansione della tilde deriva dalla shell C.

Se una parola inizia con il simbolo tilde (`~') si cerca di interpretare quello che segue, fino alla prima barra obliqua (`/'), come un nominativo-utente, facendo in modo di sostituire questa prima parte con il nome della directory personale dell'utente stesso. In alternativa, se dopo il carattere `~' c'è subito la barra, o nessun altro carattere, si intende il contenuto della variabile `HOME', ovvero la directory personale dell'utente attuale.

Esempi

cd ~

Corrisponde a uno spostamento nella directory personale dell'utente.

cd ~tizio

Corrisponde a uno spostamento nella directory personale dell'utente `tizio' (ammesso che i permessi lo consentano).

Il carattere tilde viene usato anche per altri tipi di sostituzioni, e precisamente: la coppia `~+' viene sostituita con il contenuto di `PWD', mentre, la coppia `~-' viene sostituita con il contenuto di `OLDPWD'.

45.3.4 Espansione di parametri e variabili

Il modo normale in cui si fa riferimento a un parametro o a una variabile è quello di anteporvi il simbolo dollaro (`$'), ma questo metodo può creare problemi all'interno delle stringhe, oppure quando si tratta di un parametro posizionale composto da più di una cifra decimale. La sintassi normale è quindi la seguente:

$<parametro> | ${<parametro>}

$<variabile> | ${<variabile>}

In uno di questi modi si ottiene quindi la sostituzione del parametro o della variabile con il suo contenuto.

Esempi

#!/bin/bash
echo " 1 arg. = $1"
echo " 2 arg. = $2"
echo " 3 arg. = $3"
...
echo "10 arg. = ${10}"
echo "11 arg. = ${11}"

Visualizza in sequenza l'elenco degli argomenti ricevuti, fino all'undicesimo.

---------

#!/bin/bash
UNO="Dani"
echo "${UNO}ele"

Compone la parola `Daniele' unendo il contenuto di una variabile con una terminazione costante.

Con la shell Bash, i modi in cui è possibile ottenere la sostituzione di parametri e variabili sono numerosi. Questi sono derivati generalmente dalla shell Korn e sono descritti nella sezione 47.4.

45.3.5 Sostituzione dei comandi

La sostituzione dei comandi consente di utilizzare quanto emesso attraverso lo standard output da un comando. Ci sono due forme possibili, la prima derivata dalla shell Korn e la seconda originaria della shell Bourne.

$(<comando>)

`<comando>`

Nel secondo caso dove si utilizzano gli apici inversi, la barra obliqua inversa (`\'), che fosse contenuta eventualmente nella stringa, mantiene il suo significato letterale a eccezione di quando è seguita dai simboli `$', ``' o `\'.

Bisogna fare attenzione a non confondere gli apici usati per la sostituzione dei comandi con quelli usati per la protezione delle stringhe.

La sostituzione dei comandi può essere annidata. Per farlo, se si utilizza il vecchio metodo degli apici inversi, occorre fare precedere a quelli più interni il simbolo di escape, ovvero la barra obliqua inversa.

Se la sostituzione appare tra apici doppi, la suddivisione in parole e l'espansione di percorso non sono eseguite nel risultato.

Esempi

ELENCO=$(ls)

Crea e assegna alla variabile `ELENCO' l'elenco dei file della directory corrente.

ELENCO=$(ls "a*")

Crea e assegna alla variabile `ELENCO' l'elenco dell'unico file `a*', ammesso che esista.

rm $( find / -name "*.tmp" )

Elimina da tutto il filesystem i file che hanno l'estensione `.tmp'. Per farlo utilizza `find' che genera un elenco di tutti i nomi che soddisfano la condizione di ricerca.

45.3.6 Espansione di espressioni aritmetiche

Le espressioni aritmetiche consentono la valutazione delle espressioni stesse e l'espansione utilizzando il risultato. Esistono due forme per rappresentare la sostituzione tramite espressione aritmetica: nella prima l'espressione viene racchiusa tra parentesi quadre, nella seconda tra doppie parentesi tonde.

$[<espressione>]

$((<espressione>))

L'espressione viene trattata come se fosse racchiusa tra apici doppi, ma un apice doppio all'interno delle parentesi non viene interpretato in modo speciale. Tutti gli elementi all'interno dell'espressione sono sottoposti all'espansione di parametri, variabili, sostituzione di comandi ed eliminazione di simboli superflui per la protezione. La sostituzione aritmetica può essere annidata. Se l'espressione aritmetica non è valida, si ottiene una segnalazione di errore senza alcuna sostituzione.

Esempi

echo "$((123+23))"

Emette il numero 146 corrispondente alla somma di 123 e 23.

VALORE=$[123+23]

Assegna alla variabile `VALORE' la somma di 123 e 23.

echo "$[123*$VALORE]"

Emette il prodotto di 123 per il valore contenuto nella variabile `VALORE'.

45.3.7 Suddivisione di parole

La shell esegue la suddivisione in parole dei risultati delle espansioni di parametri e variabili, della sostituzione di comandi e delle espansioni aritmetiche, che non siano avvenuti all'interno di stringhe protette attraverso la delimitazione con apici doppi.

La shell considera ogni carattere contenuto all'interno di `IFS' come un possibile delimitatore utile a determinare i punti in cui effettuare la separazione in parole.

Perché le cose funzionino così come si è abituati, è necessario che `IFS' contenga i valori predefiniti: <Spazio><Tab><newline> (ovvero <SP><HT><LF>). La variabile `IFS' è quindi importantissima: non può mancare o essere vuota.

Esempi

/$ Pippo="b* d*"[Invio]

/$ echo $Pippo[Invio]

In questo caso, avviene la suddivisione in parole del risultato dell'espansione della variabile `Pippo'. In pratica, è come se si facesse: `echo b* d*'. Il risultato è il seguente:

bin boot dev

---------

/$ echo "$Pippo"[Invio]

In questo caso non avviene la suddivisione in parole di quanto contenuto tra la coppia di apici doppi, e di conseguenza non può avvenire la successiva espansione di percorso.

b* d*

---------

/$ echo '$Pippo'[Invio]

Se si utilizzano gli apici semplici, non avviene alcuna sostituzione della variabile `Pippo'.

$Pippo

45.3.8 Espansione di percorso

Dopo la suddivisione in parole, la shell Bash scandisce ogni parola per la presenza dei simboli `*', `?' e `['. Se incontra uno di questi caratteri, la parola che li contiene viene trattata come modello e sostituita con un elenco ordinato alfabeticamente di percorsi corrispondenti al modello. Se non si ottiene alcuna corrispondenza, il comportamento predefinito è tale per cui la parola resta immutata, consentendo quindi l'utilizzo dei caratteri jolly per il globbing (i metacaratteri) per identificare un percorso. *2*

Per convenzione, si considerano nascosti i file e le directory che iniziano con un punto. Per questo, normalmente, i caratteri jolly non permettono di includere i nomi che iniziano con tale punto. Se necessario, questo punto deve essere indicato espressamente.

La barra obliqua di separazione dei percorsi non viene mai generata automaticamente dal globbing.

Caratteri jolly, o metacaratteri

*

Corrisponde a qualsiasi stringa, compresa la stringa vuota.

?

Corrisponde a un qualsiasi carattere (uno solo).

[...]

Corrisponde a uno qualsiasi dei caratteri racchiusi tra parentesi quadre.

[a-z]

Corrisponde a uno qualsiasi dei caratteri compresi nell'intervallo da a a z.

[!...]

Corrisponde a tutti i caratteri esclusi quelli indicati.

[!a-z]

Corrisponde a tutti i caratteri esclusi quelli appartenenti all'intervallo indicato.

Per includere il trattino o la parentesi quadra chiusa in un raggruppamento tra parentesi quadre, occorre che questi simboli siano i primi o gli ultimi.

45.4 Eliminazione dei simboli di protezione rimanenti

Al termine dei vari processi di espansione, tutti i simboli usati per la protezione (`\', ``' e `"') che a loro volta non siano stati protetti attraverso l'uso della barra obliqua inversa o di virgolette di qualche tipo, vengono rimossi.

---------------------------

Appunti Linux 2000.04.12 --- Copyright © 1997-2000 Daniele Giacomini --  daniele @ pluto.linux.it


1.) In un certo senso si potrebbe dire che si tratti anche in questo caso di un carattere di escape: toglie il significato normale che si dà al codice di interruzione di riga.

2.) In generale, sarebbe meglio essere precisi quando si vuole indicare espressamente un nome che contiene effettivamente un asterisco o un punto interrogativo: si deve usare la barra obliqua inversa che funge da carattere di escape.


[inizio] [indice generale] [precedente] [successivo] [indice analitico] [contributi]