9.3. Sostituzione di parametro

Manipolare e/o espandere le variabili

${parametro}

Uguale a $parametro, cioè, valore della variabile parametro. In alcuni contesti funziona solo la forma meno ambigua ${parametro}.

Può essere utilizzato per concatenare delle stringhe alle variabili.

tuo_id=${USER}-su-${HOSTNAME}
echo "$tuo_id"
#
echo "Vecchio \$PATH = $PATH"
PATH=${PATH}:/opt/bin  # Aggiunge /opt/bin a $PATH per la durata dello script.
echo "Nuovo \$PATH = $PATH"

${parametro-default}, ${parametro:-default}

Se parametro non è impostato, viene impostato al valore fornito da default.

echo ${nomeutente-`whoami`}
#  Visualizza il risultato del comando `whoami`, se la variabile 
#+ $nomeutente non è ancora impostata.

Nota

${parametro-default} e ${parametro:-default} sono quasi uguali. L'aggiunta dei : serve solo quando parametro è stato dichiarato, ma non impostato.

#!/bin/bash
# param-sub.sh

#  Il fatto che una vairabile sia stata dichiarata
#+ influenza l'uso dell'opzione preimpostata,
#+ anche se la variabile è nulla.

nomeutente0=
echo "nomeutente0 è stata dichiarata, ma contiene un valore nullo."
echo "nomeutente0 = ${nomeutente0-`whoami`}"
# Non visualizza niente.

echo

echo nomeutente1 non è stata dichiarata.
echo "nomeutente1 = ${nomeutente1-`whoami`}"
# Viene visualizzato.

nomeutente2=
echo "nomeutente2 è stata dichiarata, ma contiene un valore nullo."
echo "nomeutente2 = ${nomeutente2:-`whoami`}"
#
# Viene visualizzato perché sono stati utilizzati :- al posto del semplice -.
# Confrontatelo con il primo esempio visto sopra.


#

# Ancora una volta:

variabile=
# variabile è stata dichiarata, ma contiene un valore nullo."

echo "${variabile-0}"    # (nessun output)
echo "${variabile:-1}"   # 1
#                ^

unset variabile

echo "${variabile-2}"    # 2
echo "${variabile:-3}"   # 3

exit 0

Il costrutto parametro-default viene utilizzato per fornire agli script gli argomenti "dimenticati" da riga di comando.

DEFAULT_NOMEFILE=generico.dat
nomefile=${1:-$DEFAULT_NOMEFILE}
#  Se non diversamente specificato, il successivo blocco di 
#+ comandi agisce sul file "generico.dat".
#
#  Seguono comandi.

Vedi anche Esempio 3-4, Esempio 28-2 e Esempio A-6.

Si confronti questo metodo con l'uso di una lista and per fornire un argomento di default.

${parametro=default}, ${parametro:=default}

Se parametro non è impostato, viene impostato al valore fornito da default.

Le due forme sono quasi equivalenti. I : servono solo quando $parametro è stato dichiarato, ma non impostato, [1] come visto in precedenza.

echo ${nomeutente=`whoami`}
# La variabile "nomeutente" è stata ora impostata con `whoami`.

${parametro+altro_valore}, ${parametro:+altro_valore}

Se parametro è impostato, assume altro_valore, altrimenti viene impostato come stringa nulla.

Le due forme sono quasi equivalenti. I : servono solo quando parametro è stato dichiarato, ma non impostato. Vedi sopra.

echo "###### \${parametro+altro_valore} ########"
echo

a=${param1+xyz}
echo "a = $a"      # a =

param2=
a=${param2+xyz}
echo "a = $a"      # a = xyz

param3=123
a=${param3+xyz}
echo "a = $a"      # a = xyz

echo
echo "###### \${parametro:+altro_valore} ########"
echo

a=${param4:+xyz}
echo "a = $a"      # a =

param5=
a=${param5:+xyz}
echo "a = $a"      # a =
# Risultato diverso da   a=${param5+xyz}

param6=123
a=${param6:+xyz}
echo "a = $a"      # a = xyz

${parametro?msg_err}, ${parametro:?msg_err}

Se parametro è impostato viene usato, altrimenti visualizza un messaggio d'errore (msg_err).

Le due forme sono quasi equivalenti. I : servono solo quando parametro è stato dichiarato, ma non impostato. Come sopra.

Esempio 9-15. Sostituzione di parametro e messaggi d'errore

#!/bin/bash

#  Verifica alcune delle variabili d'ambiente di sistema.
#  È una buona misura preventiva.
#  Se, per sempio, $USER, il nome dell'utente corrente, non è impostata,
#+ la macchina non può riconoscervi.

: ${HOSTNAME?} ${USER?} ${HOME?} ${MAIL?}
  echo
  echo "Il nome della macchina è $HOSTNAME."
  echo "Tu sei $USER."
  echo "La directory home è $HOME."
  echo "La cartella di posta INBOX si trova in $MAIL."
  echo
  echo "Se leggete questo messaggio, vuol dire che"
  echo "le variabili d'ambiente più importanti sono impostate."
  echo
  echo

# ------------------------------------------------------

#  Il costrutto ${nomevariabile?} può verificare anche
#+ le variabili impostate in uno script.

QuestaVariabile=Valore-di-Questa-Variabile
#  È da notare, en passant, che le variabili stringa possono contenere
#+ caratteri che non sono consentiti se usati nei loro nomi .
: ${QuestaVariabile?}
echo "Il valore di QuestaVariabile è $QuestaVariabile".
echo
echo


: ${ZZXy23AB?"ZZXy23AB non è stata impostata."}
#  Se ZZXy23AB non è stata impostata,
#+ allora lo script termina con un messaggio d'errore.

# Il messaggio d'errore può essere specificato.
# : ${nomevariabile?"MESSAGGIO D'ERRORE"}


#  Stesso risultato con:
#+     finta_variabile=${ZZXy23AB?}
#+     finta_variabile=${ZZXy23AB?"ZXy23AB non è stata impostata."}
#
#      echo ${ZZXy23AB?} >/dev/null

#  Confrontate questi metodi per la verifica dell'impostazione di una variabile
#+ con "set -u" . . .



echo "Questo messaggio non viene visualizzato perché lo script è già terminato."

QUI=0
exit $QUI   # NON termina in questo punto.

# Infatti lo script restituisce come exit status (echo $?) 1.

Esempio 9-16. Sostituzione di parametro e messaggi "utilizzo"

#!/bin/bash
# usage-message.sh

: ${1?"Utilizzo: $0 ARGOMENTO"}
#  Lo script termina qui, se non vi è un parametro da riga di comando,
#+ e viene visualizzato il seguente messaggio d'errore.
#    usage-message.sh: 1: Utilizzo: usage-message.sh ARGOMENTO

echo "Queste due righe vengono visualizzate solo se è stato 
fornito un argomento."
echo "argomento da riga di comando = \"$1\""

exit 0  #  Lo script termina a questo punto solo se è stato 
        #+ eseguito con l'argomento richiesto.

# Verificate l'exit status dello script eseguito, sia con che senza argomento.
# Se il parametro è stato fornito, allora  "$?" è  0.
# Altrimenti "$?" è 1.

Sostituzione e/o espansione di parametro. Le espressioni che seguono sono il complemento delle operazioni sulle stringhe del costrutto match con expr (vedi Esempio 15-9). Vengono per lo più usate per la verifica dei nomi dei file.

Lunghezza della variabile / rimozione di sottostringa

${#var}

Lunghezza della stringa (numero dei caratteri di $var). Nel caso di un array, ${#array} rappresenta la lunghezza del primo elemento dell'array.

Nota

Eccezioni:

  • ${#*} e ${#@} forniscono il numero dei parametri posizionali.

  • Per gli array, ${#array[*]} e ${#array[@]} forniscono il numero degli elementi che compongono l'array.

Esempio 9-17. Lunghezza di una variabile

#!/bin/bash
# length.sh

E_NO_ARG=65

if [ $# -eq 0 ]  # Devono essere forniti degli argomenti allo script.
then
  echo "Siete pregati di seguire lo script con uno o più argomenti."
  exit $E_NO_ARG
fi  

var01=abcdEFGH28ij
echo "var01 = ${var01}"
echo "Lunghezza di var01 = ${#var01}"
# Proviamo ora ad inserire uno spazio.
var02="abcd EFGH28ij"
echo "var02 = ${var02}"
echo "Lunghezza di var02 = ${#var02}"

echo "Numero di argomenti passati allo script = ${#@}"
echo "Numero di argomenti passati allo script = ${#*}"

exit 0
${var#Modello}, ${var##Modello}

Toglie da $var la parte più breve/lunga di $Modello verificata all'inizio di $var.

Una dimostrazione del suo impiego tratta dall'Esempio A-7:

# Funzione dall'esempio "days-between.sh".
# Toglie lo/gli zeri iniziali dall'argomento fornito.

toglie_zero_iniziale () #  Toglie possibili zeri iniziali
{                       #+ dagli argomenti passati.
  return=${1#0}         #  "1" stà per $1 -- l'argomento passato.
}                       #  "0" indica ciò che va tolto da "$1" -- gli zeri.

Variante, più elaborata dell'esempio precedente, di Manfred Schwarb:

toglie_zero_iniziale2 () #  Toglie possibili zeri iniziali, altrimenti
{                        #+ Bash interpreta tali numeri come valori ottali.
  shopt -s extglob       #  Abilita il globbing esteso.
  local val=${1##+(0)}   #  Usa una variabile locale, verifica d'occorrenza più
                         #+ lunga delle serie di 0.
  shopt -u extglob       #  Disabilita il globbing esteso.
  _toglie_zero_iniziale2=${val:-0}
                         #  Nel caso l'input sia 0, restituisce 0 invece di "".
}

Altro esempio di utilizzo:

echo `basename $PWD`        # Nome della directory di lavoro corrente.
echo "${PWD##*/}"           # Nome della directory di lavoro corrente.
echo
echo `basename $0`          # Nome dello script.
echo $0                     # Nome dello script.
echo "${0##*/}"             # Nome dello script.
echo
nomefile=test.dat
echo "${nomefile##*.}"      # dat
                            # Estensione del nome del file.

${var%Modello}, ${var%%Modello}

Toglie da $var la parte più breve/lunga di $Modello verificata alla fine di $var.

La versione 2 di Bash ha introdotto delle opzioni aggiuntive.

Esempio 9-18. Ricerca di corrispondenza nella sostituzione di parametro

#!/bin/bash
# patt-matching.sh

#  Ricerca di corrispondenza utilizzando gli operatori si sostituzione
#+ di parametro # ##  % %%.

var1=abcd12345abc6789
modello1=a*c  #  * (carattere jolly) verifica tutto quello che
              #+ è compreso tra a - c.

echo
echo "var1 = $var1"           # abcd12345abc6789
echo "var1 = ${var1}"         # abcd12345abc6789
                              # (forma alternativa)
echo "Numero di caratteri in ${var1} = ${#var1}"
echo

echo "modello1 = $modello1"   # a*c  (tutto ciò che è compreso tra 'a' e 'c')
echo "--------------"
echo '${var1#$modello1}  =' "${var1#$modello1}"    # d12345abc6789
#  All'eventuale occorrenza più corta, toglie i primi 3 caratteri
#+ abcd12345abc6789                             ^^^^^
#  |-|
echo '${var1##$modello1} =' "${var1##$modello1}"   # 6789      
#  All'eventuale occorrenza più lunga, toglie i primi 12 caratteri
#+ abcd92345abc6789                             ^^^^^
#+ |----------|

echo; echo; echo

modello2=b*9            # tutto quello che si trova tra 'b' e '9'
echo "var1 = $var1"     # Ancora  abcd12345abc6789
echo
echo "modello2 = $modello2"
echo "--------------"

echo '${var1%modello2}  =' "${var1%$modello2}"     #     abcd12345a
#  All'eventuale occorrenza più corta, toglie gli ultimi 6 caratteri
#+ abcd12345abc6789                               ^^^^^^
#+           |----|
echo '${var1%%modello2} =' "${var1%%$modello2}"    #     a
#  All'eventuale occorrenza più lunga, toglie gli ultimi 15 caratteri
#+ abcd12345abc6789                               ^^^^^^
#+  |-------------|

#  Ricordate, # e ## agiscono sulla parte iniziale della stringa 
#+            (da sinistra verso destra), % e %% agiscono sulla parte 
#+            finale della stringa (da destra verso sinistra).

echo

exit 0

Esempio 9-19. Rinominare le estensioni dei file:

#!/bin/bash
# rfe.sh: Rinomuinare le estensioni dei file.
#
#         rfe vecchia_estensione nuova_estensione
#
# Esempio:
# Per rinominare tutti i file *.gif della directory di lavoro in *.jpg,
#          rfe gif jpg


E_ERR_ARG=65

case $# in
  0|1)             # La barra verticale, in questo contesto, significa "or".
  echo "Utilizzo: `basename $0` vecchia_estensione nuova_estensione"
  exit $E_ERR_ARG  # Se gli argomenti sono 0 o 1, interrompe lo script.
  ;;
esac

for nomefile in *.$1
# Passa in rassegna l'elenco dei file che terminano con il 1mo argomento.
do
  mv $nomefile ${nomefile%$1}$2
  #  Toglie la parte di nomefile che verifica il 1mo argomento,
  #+ quindi aggiunge il 2do argomento.
done

exit 0

Espansione di variabile / Sostituzione di sottostringa

I costrutti seguenti sono stati adottati da ksh.

${var:pos}

La variabile var viene espansa iniziando da pos.

${var:pos:lun}

Espansione di un massimo di lun caratteri della variabile var, iniziando da pos. Vedi Esempio A-14 per una dimostrazione dell'uso creativo di questo operatore.

${var/Modello/Sostituto}

La prima occorrenza di Modello in var viene rimpiazzata da Sostituto.

Se si omette Sostituto allora la prima occorrenza di Modello viene rimpiazzata con niente, vale a dire, cancellata.

${var//Modello/Sostituto}

Sostituzione globale. Tutte le occorrenze di Modello presenti in var vengono rimpiazzate da Sostituto.

Come prima, se si omette Sostituto allora tutte le occorrenze di Modello vengono rimpiazzate con niente, vale a dire, cancellate.

Esempio 9-20. Utilizzare la verifica di occorrenza per controllare stringhe arbitrarie

#!/bin/bash

var1=abcd-1234-defg
echo "var1 = $var1"

t=${var1#*-*}
echo "var1 (viene tolto tutto ciò che si trova prima del primo"
echo "trattino, compreso) = $t"
#  t=${var1#*-}  Dà lo stesso risultato,
#+ perché # verifica la stringa più corta,
#+ e * verifica tutto quello che sta prima, compresa una stringa vuota.
# (Grazie a Stephane Chazelas per la puntualizzazione.)

t=${var1##*-*}
echo "Se var1 contiene un \"-\", viene restituita una stringa vuota..."
echo "var1 = $t"


t=${var1%*-*}
echo "var1 (viene tolto tutto ciò che si trova dopo l'ultimo"
echo "trattino, compreso) = $t"

echo

# -------------------------------------------
percorso=/home/bozo/idee/pensieri.di.oggi
# -------------------------------------------
echo "percorso = $percorso"
t=${percorso##/*/}
echo "percorso senza tutti i prefissi = $t"
#  Stesso risultato con  t=`basename $percorso` , in questo caso particolare.
#  t=${percorso%/}; t=${t##*/}  è una soluzione più generica,
#+ ma talvolta potrebbe non funzionare.
#  Se $percorso termina con un carattere di ritorno a capo, allora 
#+ `basename $percorso` fallisce, al contrario dell'espressione precedente.
#  (Grazie, S.C.)

t=${percorso%/*.*}
# Stesso risultato di   t=`dirname $percorso`
echo "percorso a cui è stato tolto il suffisso (/pensieri.di.oggi)  = $t"
#  Questi operatori possono non funzionare, come nei casi"../", 
#+ "/foo////", # "foo/", "/". Togliere i suffissi, specialmente quando 
#+ basename non ne ha, ma dirname sì, complica la faccenda.
# (Grazie, S.C.)

echo

t=${percorso:11}
echo "$percorso, senza i primi 11 caratteri = $t"
t=${percorso:11:5}
echo "$percorso, senza i primi 11 caratteri e ridotto alla \
lunghezza di 5 caratteri = $t"

echo

t=${percorso/bozo/clown}
echo "$percorso con \"bozo\" sostituito da \"clown\" = $t"
t=${percorso/oggi/}
echo "$percorso con \"oggi\" cancellato = $t"
t=${percorso//o/O}
echo "$percorso con tutte le o minuscole cambiate in O maiuscole = $t"
t=${percorso//o/}
echo "$percorso da cui sono state cancellate tutte le o = $t"

exit 0
${var/#Modello/Sostituto}

Se il prefisso di var è verificato da Modello, allora Sostituto rimpiazza Modello.

${var/%Modello/Sostituto}

Se il suffisso di var è verificato da Modello, allora Sostituto rimpiazza Modello.

Esempio 9-21. Verifica di occorrenza di prefissi o suffissi di stringa

#!/bin/bash
# var-match.sh:
# Dimostrazione di sostituzione di occorrenza di prefisso/suffisso di stringa.

v0=abc1234zip1234abc    # Variabile originale.
echo "v0 = $v0"         # abc1234zip1234abc
echo

# Verifica del prefisso (inizio) della stringa.
v1=${v0/#abc/ABCDEF}    # abc1234zip1234abc
                        # |-|
echo "v1 = $v1"         # ABCDEF1234zip1234abc
                        # |----|

# Verifica del suffisso (fine) della stringa.
v2=${v0/%abc/ABCDEF}    # abc1234zip123abc
                        #              |-|
echo "v2 = $v2"         # abc1234zip1234ABCDEF
                        #               |----|

echo

#  ---------------------------------------------------------
#  La verifica deve avvenire all'inizio/fine della stringa,
#+ altrimenti non verrà eseguita alcuna sostituzione.
#  ---------------------------------------------------------
v3=${v0/#123/000}       # È verificata, ma non all'inizio.
echo "v3 = $v3"         # abc1234zip1234abc
                        # NESSUNA SOSTITUZIONE.
v4=${v0/%123/000}       # È stata verificata, ma non alla fine.
echo "v4 = $v4"         # abc1234zip1234abc
                        # NESSUNA SOSTITUZIONE.

exit 0
${!prefissovar*}, ${!prefissovar@}

Verifica tutte le variabili precedentemente dichiarate i cui nomi iniziano con prefissovar.

xyz23=qualsiasi_cosa
xyz24=

a=${!xyz*}      #  Espande i nomi delle variabili dichiarate che iniziano 
                #+ con "xyz".
echo "a = $a"   # a = xyz23 xyz24
a=${!xyz@}      # Come prima.
echo "a = $a"   # a = xyz23 xyz24

# La versione 2.04 di Bash possiede questa funzionalità.

Note

[1]

Se $parametro è nullo, in uno script non interattivo, quest'ultimo viene terminato con exit status 127 (il codice di errore Bash di "command not found").