Saltar la navegación

Expansión de parámetros y variables

El bash utiliza variables como cualquier otro lenguaje de programación, aunque no lo sea extrictamente, y estas pueden ser de dos tipos:

  • Variables del sistema (PATH, HOME, etc.). Por convenio suelen escribirse en mayúsculas.
  • Variables del usuario. Por convenio suelen escribirse en minúsculas.

Lo que vamos a ver en este punto es cómo sacar el valor que hay en una variable para utilizarlo, y esto se consigue con la expansión de parámetros y variables (dejamos lo parámetros para más adelante, son un caso particular de variables).

El carácter $ inicia la expansión de variables. El nombre de la variable puede ser encerrado entre llaves, esto es opcional, y sirve para evitar que el shell se confunda en los casos en los que el nombre de la variable va junto otros caracteres que no forman parte de él, y de esta forma se separa.

La forma básica de la expansión de variables es ${var} y se sustituye por el valor de var. Las llaves son obligatorias cuando la variable es seguida por un carácter que no debe ser interpretado como parte de su nombre.

$ echo $PATH
/home/usuario/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
$ echo ${PATH}
/home/usuario/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

En el caso anterior, las llaves no son obligatorias, pero supongamos que me interesa mostrar el nombre de mi máquina terminado con el dígito 1, en este caso, como se ve en el ejemplo, sí sería obligatorio meter entre llaves el nombre de la variable:

$ echo $HOSTNAME
dpto
$ echo $HOSTNAME1

$ echo ${HOSTNAME}1
dpto1

Si al nombre de la variable se le precede con una exclamación de cierre (!), se realiza una indirección de variables de un nivel. El shell expande la variable y el valor obtenido lo trata como si fuera el nombre de otra variable y la vuelve a expandir. La exclamación de cierre debe ir inmediatamente a continuación de la llave izquierda para que indique la indirección. El formato general sería: ${!var}.

$ a=b
$ b=Hola
$ echo ${a}
b
$ echo ${!a}
Hola

En todos los casos que se van a ver a continuación, 'palabra' se somete a expansión de tildes, expansión de parámetros y variables, sustitución de comandos y expansión aritmética antes de producirse la expansión que explicamos aquí:

  • ${variable:-palabra}

Denominado valor por defecto. Si variable existe y tiene valor, se expande por el valor de variable, de otro modo, se expande por palabra.

En el siguiente ejemplo ANCHO recibirá el valor de COLUMNS si lo tiene, y en caso contrario, el valor 80. Nos aseguramos que ANCHO siempre tendrá un valor.

ANCHO=${COLUMNS:-80}
  • ${variable:=palabra}

Denominado asignación del valor por defecto. Si variable existe y tiene valor, se expande por el valor de variable, de otro modo, a variable se le asigna palabra y se expande por palabra.

Si el ejemplo anterior, lo construimos con este tipo de expansión:

ANCHO=${COLUMNS:=80}

entonces ANCHO tendrá el mismo valor que antes, es decir, el valor de COLUMNS si tiene algo, u 80 en caso contrario, y en este último caso, cuando COLUMNS no tiene nada, esta variable también recibirá el valor 80.

También, se podría usar esta expansión así:

: ${COLUMNS:=80}

Con esto lo que se pretende es que COLUMNS acabe con un valor, si ya lo tenía, lo mantiene, y si no, recibe el valor 80. ¿Y qué pasa con el valor expandido?, en realidad no lo queremos para nada, es un caso distinto al anterior, por lo tanto, usamos el comando nulo, los dos puntos (:), para que no se haga nada. El comando nulo es el que recibe el valor de la expansión como su argumento y como su función es no hacer nada, conseguimos lo que perseguíamos.

  • ${variable:?palabra}

Denominado mensaje de error. Si variable existe y tiene valor, se expande por el valor de variable, de otro modo, se escribe en la salida estándar de error palabra  y el shell, si no es interactivo, termina.

: ${COLUMNS:?"Error: no se han especificado las columnas"}

En el ejemplo anterior se ha usado la orden nula, que ya conocemos, pero antes de su ejecución, como siempre, se ha realizado la expansión, provocando un error si COLUMNS no tiene nada.

La sintaxis de la orden nula es:

:  cualquier cosa
  • ${variable:+palabra}

Denominado valor alternativo. Si variable existe y tiene valor, se expande palabra, de otro modo, no realiza ninguna expansión. La idea es usar un valor alternativo solo en el caso de que existiera un valor determinado.

  • ${variable:desplazamiento}
  • ${variable:desplazamiento:longitud}

Denominado subcadena. Expande hasta longitud caracteres de variable comenzando por el carácter especificado por desplazamiento (el primer carácter es el 0). Si se omite longitud, expande hasta el final de variable. Longitud y desplazamiento tienen que ser números.

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
$ echo ${PATH:0:14}
/usr/local/bin
$ echo ${PATH:15}
/usr/bin:/bin:/usr/local/games:/usr/games
  • ${!prefijo*}

Se expande a una lista de nombres de variables cuyos nombres comiencen con prefijo, separados por el primer carácter de la variable del sistema IFS.

$ IFS=:
$ echo "${!P*}"
PATH:PIPESTATUS:PPID:PS1:PS2:PS4:PWD

En el ejemplo anterior, es fundamental utilizar las dobles comillas, para indicar que la expansión constituirá una sola palabra, pues en caso contrario, tras la expansión de variable, actuaría la división de palabras sobre el resultado de la expansión, la cual utilizará los caracteres de IFS para dividir, y en consecuencia, el carácter dos puntos desaparecerá. Podemos verlo a continuación:

$ IFS=:
$ echo ${!P*}
PATH PIPESTATUS PPID PS1 PS2 PS4 PWD
  • ${#variable}

Se expande por la longitud de caracteres que tiene el valor de variable.

$ echo $HOSTNAME
dpto
$ echo ${#HOSTNAME}
4
  • ${variable#palabra}
  • ${variable##palabra}

Palabra se expande para producir un patrón del estilo de la expansión de nombres de ficheros. Si el patrón encaja con el principio del valor expandido de variable, entonces el resultado de la expansión es el valor expandido de variable al que se le elimina el ajuste más corto al patrón (en el caso de usar '#') o el ajuste más largo al patrón (en el caso de '##').

En otras palabras, elimina por la izquierda de variable la cadena más corta (#) o más larga (##) que cuadra con el patrón palabra.

  • ${variable%palabra}
  • ${variable%%palabra}

Es igual que con # pero tomando la derecha como referencia. Es decir, elimina por la derecha de variable la cadena más corta (%) o más larga (%%) que cuadra con el patrón palabra.

  • ${variable/patrón/cadena}

patrón se expande para producir un patrón como en la expansión de nombres de ficheros; variable se expande y el ajuste más largo al patrón de este valor es sustituido por cadena. Si el patrón comienza con '/', todos los ajustes al patrón son reemplazados por cadena. Normalmente solo se reemplaza el primer ajuste. Si el patrón comienza con #, este debe encajar al principio del valor expandido de variable. Si el patrón comienza con %, este debe ajustar al final del valor expandido de variable. Si cadena es nula, los ajustes al patrón serán eliminados y se puede omitir la '/' posterior al patrón.

Veamos algunos ejemplos:

$ var=${!P*}
$ echo $var
PATH PIPESTATUS PPID PS1 PS2 PS4 PT6HOME PWD
$ v=${var##* }
$ echo $v
PWD
$ var=${var% *}
$ echo $var
PATH PIPESTATUS PPID PS1 PS2 PS4 PT6HOME
$ v=${var%% *}
$ echo $v
PATH
$ var=${var#* }
$ echo $var
PIPESTATUS PPID PS1 PS2 PS4 PT6HOME
$ var=${var/ /:}
$ echo $var
PIPESTATUS:PPID PS1 PS2 PS4 PT6HOME
$ var=${var// /:}
$ echo $var
PIPESTATUS:PPID:PS1:PS2:PS4:PT6HOME

 

Licencia: licencia de software libre GPL