La expansión de llaves en Bash es un mecanismo para generar cadenas de texto. En este artículo muestro ejemplos de uso para evitar tareas tediosas y repetitivas.

Los patrones a ser expandidos con llaves toman la forma de un preámbulo opcional (prefijo), seguido por una serie de cadenas separadas por coma o una secuencia de expansión entre un par de llaves, seguido de un texto posterior también opcional (posfijo). El preámbulo es prefijado a cada string contenido entre llaves, y el posfijo es agregado a cada cadena resultante, expandiendo de izquierda a derecha.

Una secuencia de expansión toma la forma {x..y[..incr]}, donde x e y son enteros o caracteres simples, e incr es un incremento opcional (entero). Cuando se utilizan enteros, la expresión se expande a cada número entre x e y inclusive. Es posible rellenar con ceros a izquierda para forzar que todas las cadenas resultantes tengan el mismo ancho. Cuando se utilizan caracteres (letras), la expresión se expande a cada letra entre x e y inclusive, según el orden del abecedario. Por supuesto ambas variables deben ser del mismo tipo (ambas enteras o ambas letras). Cuando se provee de un incremento, éste es utilizado como la diferencia entre cada término. Por defecto, el incremento es 1 ó -1 según corresponda.

Algunos ejemplos

El ejemplo básico consiste en crear directorios numéricos, por ejemplo del 1 al 12:

root@linuxito:/data/images# ll 2019/
total 0
root@linuxito:/data/images# mkdir -p 2019/{1..12}
root@linuxito:/data/images# ll 2019/
total 48
drwxr-xr-x 2 root root 4096 Feb  7 11:46 1
drwxr-xr-x 2 root root 4096 Feb  7 11:46 10
drwxr-xr-x 2 root root 4096 Feb  7 11:46 11
drwxr-xr-x 2 root root 4096 Feb  7 11:46 12
drwxr-xr-x 2 root root 4096 Feb  7 11:46 2
drwxr-xr-x 2 root root 4096 Feb  7 11:46 3
drwxr-xr-x 2 root root 4096 Feb  7 11:46 4
drwxr-xr-x 2 root root 4096 Feb  7 11:46 5
drwxr-xr-x 2 root root 4096 Feb  7 11:46 6
drwxr-xr-x 2 root root 4096 Feb  7 11:46 7
drwxr-xr-x 2 root root 4096 Feb  7 11:46 8
drwxr-xr-x 2 root root 4096 Feb  7 11:46 9

Lo mismo ocurre con las letras, por ejemplo expandiendo de la 'a' a la 'z':

root@linuxito:/tmp# mkdir borrar
root@linuxito:/tmp# ll borrar/
total 0
root@linuxito:/tmp# mkdir -p borrar/{a..z}
root@linuxito:/tmp# ll borrar/
total 104
drwxr-xr-x 2 root root 4096 Feb  7 11:46 a
drwxr-xr-x 2 root root 4096 Feb  7 11:46 b
drwxr-xr-x 2 root root 4096 Feb  7 11:46 c
drwxr-xr-x 2 root root 4096 Feb  7 11:46 d
drwxr-xr-x 2 root root 4096 Feb  7 11:46 e
drwxr-xr-x 2 root root 4096 Feb  7 11:46 f
drwxr-xr-x 2 root root 4096 Feb  7 11:46 g
drwxr-xr-x 2 root root 4096 Feb  7 11:46 h
drwxr-xr-x 2 root root 4096 Feb  7 11:46 i
drwxr-xr-x 2 root root 4096 Feb  7 11:46 j
drwxr-xr-x 2 root root 4096 Feb  7 11:46 k
drwxr-xr-x 2 root root 4096 Feb  7 11:46 l
drwxr-xr-x 2 root root 4096 Feb  7 11:46 m
drwxr-xr-x 2 root root 4096 Feb  7 11:46 n
drwxr-xr-x 2 root root 4096 Feb  7 11:46 o
drwxr-xr-x 2 root root 4096 Feb  7 11:46 p
drwxr-xr-x 2 root root 4096 Feb  7 11:46 q
drwxr-xr-x 2 root root 4096 Feb  7 11:46 r
drwxr-xr-x 2 root root 4096 Feb  7 11:46 s
drwxr-xr-x 2 root root 4096 Feb  7 11:46 t
drwxr-xr-x 2 root root 4096 Feb  7 11:46 u
drwxr-xr-x 2 root root 4096 Feb  7 11:46 v
drwxr-xr-x 2 root root 4096 Feb  7 11:46 w
drwxr-xr-x 2 root root 4096 Feb  7 11:46 x
drwxr-xr-x 2 root root 4096 Feb  7 11:46 y
drwxr-xr-x 2 root root 4096 Feb  7 11:46 z

Notar la ausencia de la 'ñ' por tratarse de un locale norteamericano.

El rellenado con ceros funciona agregando ceros a izquierda en los valores del rango:

root@linuxito:/tmp# rmdir borrar/*
root@linuxito:/tmp# mkdir -p borrar/{00..15}
root@linuxito:/tmp# ll borrar/
total 64
drwxr-xr-x 2 root root 4096 Feb  7 11:47 00
drwxr-xr-x 2 root root 4096 Feb  7 11:47 01
drwxr-xr-x 2 root root 4096 Feb  7 11:47 02
drwxr-xr-x 2 root root 4096 Feb  7 11:47 03
drwxr-xr-x 2 root root 4096 Feb  7 11:47 04
drwxr-xr-x 2 root root 4096 Feb  7 11:47 05
drwxr-xr-x 2 root root 4096 Feb  7 11:47 06
drwxr-xr-x 2 root root 4096 Feb  7 11:47 07
drwxr-xr-x 2 root root 4096 Feb  7 11:47 08
drwxr-xr-x 2 root root 4096 Feb  7 11:47 09
drwxr-xr-x 2 root root 4096 Feb  7 11:47 10
drwxr-xr-x 2 root root 4096 Feb  7 11:47 11
drwxr-xr-x 2 root root 4096 Feb  7 11:47 12
drwxr-xr-x 2 root root 4096 Feb  7 11:47 13
drwxr-xr-x 2 root root 4096 Feb  7 11:47 14
drwxr-xr-x 2 root root 4096 Feb  7 11:47 15

De esta forma cada cadena generada tiene el mismo ancho.

Veamos un ejemplo más avanzado:

root@linuxito:/tmp# rm -fr borrar/*
root@linuxito:/tmp# mkdir -p borrar/linuxito-{0800..1300..100}-xyz
root@linuxito:/tmp# ll borrar/
total 24
drwxr-xr-x 2 root root 4096 Feb 11 07:08 linuxito-0800-xyz
drwxr-xr-x 2 root root 4096 Feb 11 07:08 linuxito-0900-xyz
drwxr-xr-x 2 root root 4096 Feb 11 07:08 linuxito-1000-xyz
drwxr-xr-x 2 root root 4096 Feb 11 07:08 linuxito-1100-xyz
drwxr-xr-x 2 root root 4096 Feb 11 07:08 linuxito-1200-xyz
drwxr-xr-x 2 root root 4096 Feb 11 07:08 linuxito-1300-xyz

En este ejemplo se puede apreciar el uso de prefijo ("linuxito-"), posfijo ("-xyz") y un incremento (100).

Finalmente, algunas cuestiones particulares:

root@linuxito:/tmp# rm -fr borrar/*
root@linuxito:/tmp# mkdir -p borrar/linuxito-{090..1300..300}-xyz
root@linuxito:/tmp# ll borrar/
total 20
drwxr-xr-x 2 root root 4096 Feb 11 07:09 linuxito-0090-xyz
drwxr-xr-x 2 root root 4096 Feb 11 07:09 linuxito-0390-xyz
drwxr-xr-x 2 root root 4096 Feb 11 07:09 linuxito-0690-xyz
drwxr-xr-x 2 root root 4096 Feb 11 07:09 linuxito-0990-xyz
drwxr-xr-x 2 root root 4096 Feb 11 07:09 linuxito-1290-xyz

Aquí se pueden notar dos características interesantes de Bash. La primera es respecto al rellenado de ceros, donde se observa que Bash intenta dejar a todos los términos del mismo ancho, sin importar que en la expresión falte un cero. Esto significa que con anteponer un único cero en la variable a expandir, basta para que Bash rellene con el ancho adecuado.

Segunda cuestión: cuando se utiliza una variable de terminación (en este ejemplo 1300) que no es divisible por el incremento, o lo es pero queda desplazada respecto al valor inicial (90), Bash finaliza la generación de términos utilizando la variable de terminación como cota superior, sin incluirla como término final (notar la ausencia del término "linuxito-1300-xyz").

Gracias a las expresiones con llaves de expansión es posible evitar un programa, script o bucle para generar cientos o miles de directorios con nombres predecibles o en secuencia.

Referencias

  • man bash


Tal vez pueda interesarte


Compartí este artículo