Bash scripting - espansioni quotabili
Bash scripting |
Sommario |
Espansioni in stringhe quotate
Le espansione attivate da $
avvengono con la stessa priorità, e in una stringa quotata sono le uniche permesse, quindi il risultato di un'espansione non può mai essere espanso un'altra volta. Sono permesse le sole espansioni di variabile, già vista, e di parametro, di comando e aritmetica (intera), che saranno trattate in seguito.
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 può essere contenuta in alcune espansioni di parametro, purché non al posto del nome della variabile, mentre non è mai possibile annidare più espansioni di parametro.
Modificatori:
${#var}
ritorna il numero di caratteri della stringa contenuta in ${var}. Espande sempre a una singola stringa;${!var}
(non POSIX) ritorna il contenuto della variabile, il cui nome è contenuto in ${var} (accesso indiretto);${var:-stringa}
(valore di default, se nulla) ritorna il contenuto della variabile, se definita e non è nulla, altrimenti espande stringa, che può essere anche un'altra variabile. Non cambia il contenuto di ${var};${var-stringa}
(valore di default, se non definita) ritorna il contenuto della variabile, se definita (anche se nulla), altrimenti espande stringa, che può anche essere un'altra variabile. Non cambia il contenuto di ${var};- modificatori di assegnazione e valori alternativi, non trattati perché sconsigliati per la leggibilità del codice e non sono fondamentali. Si noti invece che l'uso dell'espansione di parametro con valore di default è l'unico modo per distinguere una variabile non definita da una nulla;
- manipolatori di stringa (rimozione, sostituzione, trasformazione in uppercase/lowercase), trattati tra breve.
Esempio:
var2=${var-stringa} # assegna stringa (perché $var non è definita) printf %s\\n "$var2" # stampa: stringa var="" # assegna a var una stringa nulla var2=${var-stringa} # assegna il contenuto (nullo) di $var (perché è definita) printf %s\\n "$var2" # stampa una riga vuota var2=${var:-stringa} # assegna stringa (perché $var è nulla) printf %s\\n "$var2" # stampa: stringa rif="var2" # rif contiene il nome (senza $) di $var2 var=${!rif} # equivalente a: var=$var2 printf %s\\n "$var" # stampa: stringa printf %s\\n ${#var} # stampa: 7 (la lunghezza di "stringa")
Manipolazione delle stringhe
Per manipolare una stringa, è possibile assegnarla a una variabile per poi effettuarne un'espansione di parametro che manipola la stringa, senza modificare il contenuto della variabile. Per esempio:
VAR="stringa-di-esempio" printf %s\\n "${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 fondamentali:
#
sottrae dall'inizio della stringa (minimale);%
sottrae dalla fine della stringa (minimale);/
(non POSIX) sostituisce una sottostringa con un'altra (solo la prima volta che viene incontrata);^
(non POSIX) trasforma in maiuscola la prima lettera della stringa (solo il primo carattere);,
(non POSIX) trasforma in minuscola la prima lettera della stringa (solo il primo carattere).
Questi operatori sono minimali, questo vuol dire che se si usano le espressioni regolari per indicare la sottostringa (da eliminare, sostituire o trasformare) verrà individuata in caso di ambiguità la sottostringa più piccola (o solo la prima nel caso di sostituzione o trasformazione).
Per ottenere gli operatori massimali basta raddoppiare il simbolo:
##
sottrae dall'inizio della stringa (massimale);%%
sottrae dalla fine della stringa (massimale);//
(non POSIX) sostituisce una sottostringa con un'altra (tutte le volte che viene incontrata);^^
(non POSIX) trasforma in maiuscola la stringa (tutta);,,
(non POSIX) trasforma in minuscola la stringa (tutta).
Gli operatori massimali cercano di individuare la sottostringa più grande che corrisponde all'espressione regolare, mentre nel caso del modificatore // tutte le sottostringhe vengono sostituite, e nel caso della trasformazione tutta la stringa e non solo il primo carattere.
Si noti che le stringhe interne a un'espansione di parametro possono essere delle variabili, ma non altre espansioni di parametro:
# cambia l'estensione nella variabile file if [ "$file" != "${file%${estensione}}" ]; then file=${file%${estensione}}${nuova_estensione} fi
Le espressioni regolari supportate sono le stesse permesse nelle espansioni di parametro e con lo stesso significato (ossia: ? * [ ]
), e con gli operatori di sottrazione c'è differenza tra quelli minimali e massimali soltanto se il pattern contiene uno o più *
, che è l'unico carattere speciale che può sostituire un numero qualsiasi (zero o più) di caratteri.
Esempio: alternativa a basename
Quando in uno script ci si deve riferire al nome dello script stesso, è usuale utilizzare il comando esterno basename
. Una possibile alternativa:
usage () { printf %s\\n "Usage: ${0##*/}" }
Esempi: manipolazione delle stringhe
VAR="questa.sarebbe.UNA.stringa.di.esempio" # Risultato: printf %s\\n "${VAR#*.}" # sarebbe.UNA.stringa.di.esempio printf %s\\n "${VAR##*.}" # esempio printf %s\\n "${VAR%.*}" # questa.sarebbe.UNA.stringa.di printf %s\\n "${VAR%%.*}" # questa printf %s\\n "${VAR/st/LL}" # queLLa.sarebbe.UNA.stringa.di.esempio printf %s\\n "${VAR//st/LL}" # queLLa.sarebbe.UNA.LLringa.di.esempio printf %s\\n "${VAR^*}" # Questa.sarebbe.UNA.stringa.di.esempio printf %s\\n "${VAR^^*}" # QUESTA.SAREBBE.UNA.STRINGA.DI.ESEMPIO printf %s\\n "${VAR,*}" # questa.sarebbe.UNA.stringa.di.esempio (invariata) printf %s\\n "${VAR,,*}" # questa.sarebbe.una.stringa.di.esempio
Per una spiegazione dettagliata di tutti i modificatori e anche di altri modi di manipolare le stringhe in Bash (ad esempio expr
) vedere:
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 $(...)
:
$(comando)
oppure, meno leggibile e sconsigliata tra `...`
(su tastiera con layout italiano: Alt Gr + '
):
`comando`
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.
Esempi di assegnazione:
# assegna alla variabile $oggi la data in formato YYYY_MM_DD oggi=$(date '+%F') # senza virgolette oggi="$(date '+%F')" # equivalente a sopra (non servono nelle assegnazioni) # associo a testo la dimensione in bytes di $file testo=$(wc -c -- $file) # SBAGLIATO! (se la variabile $file contiene spazi o caratteri speciali) testo=$(wc -c -- "$file") # le virgolette attorno alla variabile sono necessarie testo="$(wc -c -- "$file")" # equivalente a sopra # testo contiene anche altre stringhe, ma sono interessato solo alla prima bytes=${testo%% *} # estraggo il primo argomento (espansione di parametro)
Passaggio dell'output dei comandi come argomento:
# stampa stati printf %s\\n "Login name: $(logname); Name: $(whoami); UID: $(id -ur); EUID: $(id -u); Groups: $(groups)" printf %s\\n "OS: Debian GNU/Linux $(cat /etc/debian_version) ($(lsb_release -sc))" # uguale a $(lsb_release -sd) printf %s\\n "Kernel: $(uname) $(uname -r) ($(uname -v))"
Output con a capo finali
Si noti che l'espansione di comando, come anche in sh (POSIX), non espande il comando a tutto l'output prodotto, ma omette sempre gli "a capo" finali. Se da una parte è utile nella maggior parte delle situazioni, può talvolta avere effetti collaterali difficili da prevedere. Si consideri per esempio:
printf %s\\n ciao > ./file_prova # scrive ciao e un "a capo" nel file_prova testo=$(cat ./file_prova) # associa il contenuto (SENZA "a capo") a $testo printf %s\\n "Bytes: ${#testo}" # NON è la dimensione esatta del file! printf %s\\n "$testo" | # invia la stringa a cmp (più un "a capo") per un confronto cmp - ./file_prova # nessun errore!!! printf %s\\n $? # infatti stampa 0
Un altro esempio, vogliamo associare il carattere "a capo" a una variabile:
nr=" " # funziona, ma occupa più righe e rompe l'indentazione nr=$'\n' # funziona (non POSIX) ed è il modo consigliato in bash # a titolo esemplicativo per l'espansione di comando nr=$(printf \\n) # SBAGLIATO, $nr è vuota nr="$(printf \\n)" # SBAGLIATO, $nr è sempre vuota # una possibile soluzione (POSIX) nr=$(printf \\n%s X) # $nr contiene "a capo" seguito da X nr=${nr%X} # $nr contiene "a capo" (la X è rimossa) # Attenzione che il carattere aggiunto dev'essere nell'output del comando nr="$(printf \\n)X" # SBAGLIATO, $nr contiene solo X
Espansione aritmetica intera
Permette di compiere operazioni aritmetiche tra interi, ritornando sempre una singola stringa contenente l'intero risultante. Può essere quotata, ma non cambia niente.
La sintassi è: $((...))
All'interno delle parentesi è possibile utilizzare:
- le quattro operazioni:
+ - * /
- resto/modulo:
%
- potenza:
**
- variabili da espandere (contenenti valori interi)
- parentesi per cambiare le priorità degli operatori:
( )
Esempio:
base=9 altezza=5 area=$(($base * $altezza)) printf %s\\n "Area rettangolo: ${area}" # Stampa 45 printf %s\\n "Area triangolo: $(($area / 2))" # Stampa 22 (RICORDA: solo interi)
Guida scritta da: ~ The_Noise (in Bash tips) | Debianized 60% |
Estesa da: | |
Verificata da: | |
Verificare ed estendere la guida | Cos'è una guida Debianized |