XXX 10.2. Substitució de paràmetres¶
Manipulació i/o expansió de variables
${parametre}
El mateix que
$parametre
, És a dir, el valor de la variableparametre
. En certs contextos, només funciona la forma menys ambigua de `` ${parametre} ``.Es pot utilitzar per concatenar variables amb strings.
el_teu_id=${USER}-a-${HOSTNAME} echo "$el_teu_id" # echo "Antic \$PATH = $PATH" PATH=${PATH}:/opt/bin # Afegeix /opt/bin a $PATH durant l'execució del script. echo "Nou \$PATH = $PATH"
${parametre-perdefecte}
,${parametre:-perdefecte}
En cas que el paràmetre no estigui assignat, es fa servir el valor per defecte.
var1=1 var2=2 # var3 no està assignada. echo ${var1-$var2} # 1 echo ${var3-$var2} # 2 # ^ Atenció al prefix $. echo ${username-`whoami`} # Mostra el resultat de `whoami` si la variable $username no està assignada. :align: center :alt: Atenció Atenció
${parametre-perdefecte}
i${parametre:-perdefecte}
són pràcticament equivalents. Els : extra només tenen sentit quanparametre
està declarat però té assignat nul.#!/bin/bash # param-sub.sh # El fet que una variable estigui o no declarada #+ suposa l'activació de l'opció per defecte #+ fins i tot quan el valor és nul. username0= echo "username0 està declarat però té assignat el valor nul." echo "username0 = ${username0-`whoami`}" # No mostrarà res. echo echo username1 no està declarat. echo "username1 = ${username1-`whoami`}" # Mostra el valor per defecte (resultat de whoami). username2= echo "username2 està declarat però té assignat nul." echo "username2 = ${username2:-`whoami`}" # ^ # Mostra el valor per defecte donat que hem posat a la condició :- en comptes de un simple - . # Compara amb la primera instància, per sobre. # # Un cop més: variable= # variable està declarada però assignada a nul. echo "${variable-0}" # (sense sortida) echo "${variable:-1}" # 1 # ^ unset variable echo "${variable-2}" # 2 echo "${variable:-3}" # 3 exit 0
Aquesta funcionalitat de paràmetre per defecte és útil quan cal definir paràmetres “no indicats” a la línia de comandes de la crida al script.
DEFAULT_FILENAME=generic.data filename=${1:-$DEFAULT_FILENAME} # En cas que no s'indiqui el contrari, les comandes al següent bloc actuen #+ sobre el fitxer "generic.data". # Inici del bloc de comandes # ... # ... # ... # Final del bloc de comandes # De l'exemple "hanoi2.bash": DISKS=${1:-E_NOPARAM} # Cal especificar el nombre de discos. # Assigna $DISKS al paràmetre de línia de comanda $1, #+ o bé a $E_NOPARAM en cas que $1 no estigui especificat.
Mira també Exemple 3-4, Exemple 30-2, i Exemple A-6.
Compara aquest mètode amb l’ús d’una*llista “and”* per a suplir un argument de línia de comandes per defecte.
${parametre=perdefecte}
, ${parametre:=perdefecte}
En cas que el paràmetre no estigui assignat, assigna’l a perdefecte.
Les dues formes són pràcticament equivalents. El funcionament amb els : només es diferencia quan
$parametre
està declarat i assignat a nul [1] com passava més amunt.echo ${var=abc} # abc echo ${var=xyz} # abc # $var ja se li a assignat abc i per tant no canvia.
${parametre+altre_valor}
,${parametre:+altre_valor}
Si el paràmetre està assignat, canvia el valor a
altre_valor
, altrament fes servir el string nul.Les dues formes són pràcticament equivalents. El funcionament amb els : només es diferencia quan
parametre
està declarat i assignat a nul (mira més amunt).echo "###### \${parametre+altre_valor} ########" echo a=${param1+xyz} echo "a = $a" # a = param2= a=${param2+xyz} echo "a = $a" # a = xyz <t0><b1>${parameter=default}</b1></t0>, <t2><b3>${parameter:=default}</b3></t2> <t0><b1>${parametre=perdefecte}</b1></t0>, <t2><b3>${parametre:=perdefecte}</b3></t2> (50%, 50%, 82%) param3=123 a=${param3+xyz} echo "a = $a" # a = xyz echo echo "###### \${parametre:+altre_valor} ########" echo a=${param4:+xyz} echo "a = $a" # a = param5= a=${param5:+xyz} echo "a = $a" # a = # Resultat diferent de a=${param5+xyz} param6=123 a=${param6:+xyz} echo "a = $a" # a = xyz
${parametre?msg_err}
,${parametre:?msg_err}
Si el paràmetre està assignat fes servir el seu valor, altrament mostra el missatge msg_err.
Les dues formes són pràcticament equivalents. El funcionament amb els : només es diferencia quan
$parametre
està declarat i assignat a nul com passava més amunt.
Exemple 1. Ús de la substitució de paràmetres i els missatges d’error¶
#!/bin/bash
# Comprovació d'algunes variables d'entorn del sistema.
# És una bona pràctica de manteniment preventiu.
# Si, per exemple, la variable d'entorn $USER (el nom de la persona logada a la consola), no està assignada,
#+ la màquina no et podrà reconèixer!.
: ${HOSTNAME?} ${USER?} ${HOME?} ${MAIL?}
echo
echo "El nom de la màquina és $HOSTNAME."
echo "Tu ets $USER."
echo "El teu directori d'inici és $HOME."
echo "La teva carpeta d'entrada de correu es troba a $MAIL."
echo
echo "Si pots llegir aquest missatge, "
echo "vol dir que les variables d'entorn crítiques estan definides."
echo
echo
# ------------------------------------------------------
# L'expressió ${variablename?} també pot consultar
#+ si una variable està assignada dins el script.
AquestaVar=Valor-daquesta-var
# Fixat, per cert, que una variable pot ser assignada
#+ a strings amb caràcters que no estan permesos en el seu nom.
: ${AquestaVar?}
echo "El valor de AquestaVar és $AquestaVar".
echo; echo
: ${ZZXy23AB?"ZZXy23AB no està assignada."}
# Donat que ZZXy23AB no està assignada,
#+ el script finalitza amb un missatge d'error.
# Es pot especificar el missatge d'error.
# : ${nomvariable?"MISSATGE D'ERROR"}
# El mateix resultat que amb: altravariable=${ZZXy23AB?}
# altravariable=${ZZXy23AB?"ZXy23AB no està assignada."}
#
# echo ${ZZXy23AB?} >/dev/null
# Compara aquests mètodes de comprovar si una variable ha estat assignada
#+ amb "set -u" . . .
echo "Aquest missatge no es mostrarà perquè hores d'ara el script ja haurà terminat."
HERE=0
exit $HERE # NO finalitzarà aquí!.
# De fet, el script retornarà 1 com a resultat d'execució (echo $?).
Exemple 2. Ús de la substitució de paràmetres i els missatges d‘“informació”¶
#!/bin/bash
# usage-message.sh
: ${1?"Ús: $0 ARGUMENT"}
# El script finalitza aquí si falta el 1er paràmetre de línia de comandes.
#+ Mostrarà el següent missatge d'error:
# usage-message.sh: 1: Ús: usage-message.sh ARGUMENT
echo "Aquestes dues línies només s'executaran si s'ha especificat el paràmetre per línia de comandes."
echo "Paràmetre de línia de comanda = \"$1\""
exit 0 # Finalitzarà aquí només si s'ha especificar el primer paràmetre per línia de comandes.
# Pots comprovar el resultat de sortida tant passant-li el primer paràmetre per línia de comandes com no.
# Si li passes el paràmetre, "$?" serà 0.
# En cas contrari, "$?" serà 1.
Ús de la substitució de paràmetres i/o l’expansió.**Les expressions
següents complementen les operacions de strings que consideren la
**coincidència amb
expressió (mira l’Exemple 16-9). Aquestes en concret es fan servir majoritàriament en l’anàlisi de camins (path) d’arxius.
Longitud de variables / Eliminació de substrings
${#var}
Longitud del string
(nombre de caràcters a$var
). Per a un array, ${#array} correspon a la longitud del primer element de l’array.align: center alt: Atenció Atenció
Excepcions:
- ${#*} i ${#@} retornen el nombre de paràmetres.
- En cas d’array, ${#array[*]} i ${#array[@]} retornen el nombre d’elements que conté l’array.
Exemple 3. Durada d’una variable¶
#!/bin/bash # length.sh E_NO_ARGS=65 if [ $# -eq 0 ] # Per a aquesta demo cal que hi hagi arguments a la línia de comandes. then echo "Crideu aquest script amb un o més arguments." exit $E_NO_ARGS fi var01=abcdEFGH28ij echo "var01 = ${var01}" echo "Longitud de var01 = ${#var01}" # Intentem-ho ara amb un espai entre els caràcters. var02="abcd EFGH28ij" echo "var02 = ${var02}" echo "Longitud de var02 = ${#var02}" echo "Nombre d'arguments de línia de comandes passats al script = ${#@}" echo "Nombre d'arguments de línia de comandes passats al script = ${#*}" exit 0
${var#Patró}
, ${var##Patró}
${var#Patró} Elimina de
$var
la part més curta del patró que coincideixides de l'inici
amb el contingut de$var
. NdT. No he pogut comprovar aquest funcionament. A les meves proves, ${var#patró} elimina la cadena “Patró” de l’inici de $var en cas que coincideixi perfectament.${var##Patríó} Elimina de
$var
la part més llarga de$Patró
que coincideixides de l'inici
amb el contingut de$var
. NdT. No he pogut comprovar aquest funcionament. A les meves proves, ${var##Patró} es comporta idènticament a ${var#Patró} excepte en el cas que s’afegeixi el caràcter *. Ex. ${var#*Patró} no sempre resulta igual a ${var##*Patró}.Veiem un exemple d’ús a l’Exemple A-7:
# Una funció de l'exemple "days-between.sh". # Elimina els zeros inicials de l'argument. strip_leading_zero () # Elimina un possible zero inicial { #+ del paràmetre. return=${1#0} # El "1" correspon al argument "$1". } # El "0" és el que volem eliminar de "$1".Una versió de Manfred Schwarb amb una variació més elaborada de l’anterior:
strip_leading_zero2 () # Elimina els possibles zeros inicials de manera que { # Bash no els interpreti com a valors en octal. shopt -s extglob # Activa l'expansió (globbing) estesa. local val=${1##+(0)} # Guarda a la variable local val el resultat d'eliminar els 0's inicials. shopt -u extglob # Desactiva l'expansió estesa. _strip_leading_zero2=${val:-0} # En cas que l'entrada fos 0, retorna un 0 en comptes de "". }Un altre exemple d’ús:
echo `basename $PWD` # Nom del directori de treball actual (incloent el camí absolut). echo "${PWD##*/}" # Nom del directori de treball actual (només el nom) echo echo `basename $0` # Nom del script. echo $0 # Nom del script. echo "${0##*/}" # Nom del script. echo nomfitxer=test.data echo "${nomfitxer##*.}" # dades # Extensió del fitxer nomfitxer.
${var%Pattern}
, ${var%%Pattern}
${var%Pattern} elimina de
$var
la part més curta del patró$Pattern
que coincideixi amb lapart final
de$var
.${var%%Pattern} elimina de
$var
la part més llarga de$Pattern
que coincideixi amb lapart final
de$var
.
La versió 2 de Bash va afegir noves opcions.
Exemple 4. Patrons a la substitució de paràmetres¶
#!/bin/bash
# patt-matching.sh
# Patrons fent servir els operadors de substitució de paràmetres # ## % %% .
var1=abcd12345abc6789
pattern1=a*c # * (comodí) coincideix amb qualsevol cosa entre a - c.
echo
echo "var1 = $var1" # abcd12345abc6789
echo "var1 = ${var1}" # abcd12345abc6789
# (forma alternativa)
echo "Nombre de caràcters en ${var1} = ${#var1}"
echo
echo "pattern1 = $pattern1" # a*c (qualsevol cosa entre 'a' i 'c')
echo "--------------"
echo '${var1#$pattern1} =' "${var1#$pattern1}" # d12345abc6789
# La coincidència més curta possible. Elimina els tres primers caràcters abcd12345abc6789 (NdT. No l'he pogut replicar)
# ^^^^^ |-
echo '${var1##$pattern1} =' "${var1##$pattern1}" # 6789
# La coincidència més llarga possible. Elimina els primers 12 caràcters abcd12345abc6789 (NdT. No l'he pogut replicar)
# ^^^^^ |----------
echo; echo; echo
pattern2=b*9 # qualsevol cosa entre 'b' i '9'
echo "var1 = $var1" # es manté abcd12345abc6789
echo
echo "pattern2 = $pattern2"
echo "--------------"
echo '${var1%pattern2} =' "${var1%$pattern2}" # abcd12345a
# La coincidència més curta possible. Elimina els darrers 6 caràcters abcd12345abc6789
# ^^^^ |----
echo '${var1%%pattern2} =' "${var1%%$pattern2}" # a
# La coincidència més llarga possible. Elimina els darrers 12 caràcters abcd12345abc6789
# ^^^^ |-------------
# Recordem, # i ## actuen d'esquerra a dreta (des de l'inici) de la cadena,
# % i %% actuen de dreta a esquerra (des del final) de la cadena.
echo
exit 0
Exemple 5. Canvi d’extensió d’un fitxer:¶
#!/bin/bash
# rfe.sh: Canvi d'extensió d'un fitxer
#
# rfe extensio_anterior extensio_nova
#
# Exemple:
# per canviar tots els *.gif del directori actual per *.jpg,
# rfe gif jpg
E_BADARGS=65
case $# in
0|1) # Aquí la barra vertical significa disjunció "o" ("or").
echo "Ús: `basename $0` sufix_antic sufix_nou"
exit $E_BADARGS # En cas de 0 o 1 arguments.
;;
esac
for nomfitxer in *.$1
# Ordre invers de la llista de fitxers, tot començant amb el primer argument.
do
mv $nomfitxer ${nomfitxer%$1}$2
# Elimina la part del fitxer que coincideixi amb el primer argument, i
#+ a continuació afegeix el segon argument.
done
exit 0
Expansió de variables / substitució de substrings
Les següents funcions van ser adoptades del ksh.
${var:pos}
- Variable
var
expandida, començant des de la posiciópos
. ${var:pos:len}
- Expansió de
len
caràcters de la variablevar
començant des de la posiciópos
. A l’Exemple A-13 es troba un exemple (creatiu) d’ús d’aquest operador. ${var/Patró/Substitució}
Substitueix la primera aparició del
Patró
, a la variablevar
perSubstitució
.En cas que no s’especifiqui
Substitució
, la primera ocurrència dePatró
es substitueix per no res. És a dir, elimina aquesta part de la variable.${var//Patró/Substitució}
Substitució global. Substitueix totes les aparicions de
Patró
de la variablevar
perSubstitució
.Com abans, si no s’especifica
Substitució
es substitueixen totes les ocurrències dePatró
per no res. És a dir, són eliminades.
Exemple 6. Anàlisi de strings arbitraris¶
empty string. #!/bin/bash var1=abcd-1234-defg echo "var1 = $var1" t=${var1#*-*} echo "var1 (un cop eliminat la part inicial fins al primer - ) = $t" # t=${var1#*-} el string buit fa exactament el mateix, #+ donat que # coincideix amb el string més curt, #+ i * coincideix amb qualsevol cosa (incloent res) que precedeixi el string buit. # (Agraïment per Stephane Chazelas) t=${var1##*-*} echo "si var1 conté un \"-\" retornarà la cadena buida... var1 = $t" t=${var1%*-*} echo "var1 (un cop eliminat el contingut des del darrer - fins al final) = $t" echo # ------------------------------------------- path_name=/home/bozo/ideas/thoughts.for.today # ------------------------------------------- echo "path_name = $path_name" t=${path_name##/*/} echo "path_name un cop eliminat els prefixos = $t" # En aquest cas, ofereix el mateix resultat que t=`basename $path_name`. # t=${path_name%/}; t=${t##*/} és una solució més general, #+ però encara falla de vegades. # En cas que $path_name acabi amb salt de línia, no funcionarà `basename $path_name`, #+ mentre que l'expressió anterior continuarà funcionant. # (Gràcies S.C.) t=${path_name%/*.*} # El mateix resultat que t=`dirname $path_name` echo "path_name, sense l'extensió= $t" # Fallarà en alguns casos, com ara amb "../", "/foo////", # "foo/", "/". # L'eliminació de sufixos es complica especialment quan el nom base no té extensió #+ però el directori que el conté sí que en té. # (Agraïment per S.C.) echo t=${path_name:11} echo "$path_name sense els primers 11 caràcters = $t" t=${path_name:11:5} echo "$path_name sense els primers 11 caràcters i amb 5 de longitud = $t" echo t=${path_name/bozo/clown} echo "$path_name on \"bozo\" ha estat substituït per \"clown\" = $t" t=${path_name/today/} echo "$path_name on \"today\" ha estat eliminat = $t" t=${path_name//o/O} echo "$path_name on s'ha passat totes les "o" a majúscules = $t" t=${path_name//o/} echo "$path_name sense cap "o" = $t" exit 0
${var/#Patró/Substitució}
- Quan l’inici de
var
coincideix ambPatró
, llavorsSubstitució
apareix en comptes dePatró
. ${var/%Patró/Substitució}
- Quan el final de
var
coincideix ambPatró
, llavorsSubstitució
apareix en comptes dePatró
.
Exemple 7. Coincidència de patrons a l’inici o al final d’un string¶
#!/bin/bash # var-match.sh: # Demostració de la substitució del patró a l'inici/final d'un string. v0=abc1234zip1234abc # Variable original. echo "v0 = $v0" # abc1234zip1234abc echo # Coincideix amb l'inici del string. v1=${v0/#abc/ABCDEF} # abc1234zip1234abc # |- echo "v1 = $v1" # ABCDEF1234zip1234abc # |---- # Coincideix amb el final del string. v2=${v0/%abc/ABCDEF} # abc1234zip123abc # |- echo "v2 = $v2" # abc1234zip1234ABCDEF # |---- echo # ---------------------------------------------------- # Cal que coincideixi extactament amb l'inici/final del string. #+ Altrament no es realitza cap canvi. # ---------------------------------------------------- v3=${v0/#123/000} # Coincideix però no amb l'inici. echo "v3 = $v3" # abc1234zip1234abc # CAP CANVI. v4=${v0/%123/000} # Coincideix però no amb el final. echo "v4 = $v4" # abc1234zip1234abc # CAP CANVI. exit 0
${!varprefix*}
,${!varprefix@}
Coincideix amb els noms de totes les variables declarades que comencen per
varprefix
.# Es tracta d'una variació d'una referència directa que fa servir * o @. # Aquesta funcionalitat està disponible en Bash des de la versió 2.04. xyz23=elquesigui xyz24= a=${!xyz*} # Expandeix als *noms* de les variables declarades # ^ ^ ^ + que comencen per "xyz". echo "a = $a" # a = xyz23 xyz24 a=${!xyz@} # Com abans. echo "a = $a" # a = xyz23 xyz24 echo "---" abc23=algunaaltracosa b=${!abc*} echo "b = $b" # b = abc23 c=${!b} # Aquesta és la manera més habitual de fer una referència indirecta. echo $c # una_altra_cosa