Todos los administradores de sistemas probablemente tienen alguna habilidad que han aprendido a lo largo de los años que pueden señalar y decir:"Eso cambió mi mundo". Esa habilidad, o ese poco de información, o esa técnica simplemente cambió la forma en que hago las cosas. Para muchos de nosotros, eso es bucle en bash. Hay otros enfoques de la automatización que sin duda son más robustos o escalables. La mayoría de ellos no se comparan con la simplicidad y facilidad de uso del for
bucle, sin embargo.
Si desea automatizar la configuración de miles de sistemas, probablemente debería usar Ansible. Sin embargo, si intenta cambiar el nombre de miles de archivos o ejecutar el mismo comando varias veces, entonces for
loop es definitivamente la herramienta adecuada para el trabajo.
[ También te puede interesar: Dominar bucles con plantillas Jinja en Ansible ]
Si ya tiene experiencia en programación o secuencias de comandos, probablemente esté familiarizado con lo que for
los bucles sí. Si no es así, intentaré desglosarlo en un lenguaje sencillo para usted.
El concepto básico es: PARA un conjunto dado de artículos, DO una cosa.
El conjunto dado de elementos puede ser un conjunto literal de objetos o cualquier cosa que Bash pueda extrapolar a una lista. Por ejemplo, el texto extraído de un archivo, la salida de otro comando Bash o los parámetros pasados a través de la línea de comando. Convertir esta estructura de bucle en un script Bash también es trivial. En este artículo, le mostramos algunos ejemplos de cómo un for
loop puede hacerte lucir como un héroe de la línea de comandos, y luego tomamos algunos de esos ejemplos y los colocamos dentro de un script Bash más estructurado.
Estructura básica del bucle for
Primero, hablemos de la estructura básica de un for
loop, y luego veremos algunos ejemplos.
La sintaxis básica de un for
el bucle es:
for <variable name> in <a list of items>;do <some command> $<variable name>;done;
El nombre de la variable será la variable que especifique en el do
sección y contendrá el elemento en el bucle en el que se encuentra.
La lista de elementos puede ser cualquier cosa que devuelva una lista separada por espacios o saltos de línea.
He aquí un ejemplo:
$ for name in joey suzy bobby;do echo $name;done
Eso es tan simple como parece y no hay mucho que hacer allí, pero lo ayuda a comenzar. La variable $nombre contendrá el elemento en la lista en la que el bucle está operando actualmente, y una vez que el comando (o comandos) en el do
se llevan a cabo, el bucle se moverá al siguiente elemento. También puede realizar más de una acción por bucle. Cualquier cosa entre do
y done
será ejecutado. Los nuevos comandos solo necesitan un ;
delimitándolos.
$ for name in joey suzy bobby; do echo first $name;echo second $name;done;
first joey
second joey
first suzy
second suzy
first bobby
second bobby
Ahora un poco de real ejemplos.
Renombrar archivos
Este ciclo toma la salida del comando Bash ls *.pdf
y realiza una acción en cada nombre de archivo devuelto. En este caso, agregaremos la fecha de hoy al final del nombre del archivo (pero antes de la extensión del archivo).
for i in $(ls *.pdf); do
mv $i $(basename $i .pdf)_$(date +%Y%m%d).pdf
done
Para ilustrar, ejecute este bucle en un directorio que contenga estos archivos:
file1.pdf
file2.pdf
...
fileN.pdf
Los archivos se renombrarán así:
file1_20210210.pdf
file2_20210210.pdf
...
fileN_20210210.pdf
En un directorio con cientos de archivos, este ciclo le ahorra una cantidad considerable de tiempo al renombrarlos a todos.
Extrapolación de listas de elementos
Imagina que tienes un archivo que deseas scp
a varios servidores. Recuerda que puedes combinar el for
bucle con otras funciones de Bash, como la expansión de shell, que le permite a Bash expandir una lista de elementos que están en una serie. Esto puede funcionar para letras y números. Por ejemplo:
$ echo {0..10}
0 1 2 3 4 5 6 7 8 9 10
Suponiendo que sus servidores se nombran en algún tipo de patrón como, web0 , web1 , web2 , web3 , puede hacer que Bash itere la serie de números de esta manera:
$ for i in web{0..10};do scp somefile.txt ${i}:;done;
Esto iterará a través de web0 , web1 , web2 , web3 , y así sucesivamente, ejecutando su comando en cada elemento.
También puede definir algunas iteraciones. Por ejemplo:
$ for i in web{0..10} db{0..2} balance_{a..c};do echo $i;done
web0
web1
web2
web3
web4
web5
web6
web7
web8
web9
web10
db0
db1
db2
balance_a
balance_b
balance_c
También puede combinar iteraciones. Imagine que tiene dos centros de datos, uno en los Estados Unidos y otro en Canadá, y la convención de nomenclatura del servidor identifica en qué centro de datos vivía un par de servidores HA. Por ejemplo, web-us-0 sería el primer servidor web en el centro de datos de EE. UU., mientras que web-ca-0 serían web 0's contraparte en el centro de datos de CA. Para ejecutar algo en ambos sistemas, puede usar una secuencia como esta:
$ for i in web-{us,ca}-{0..3};do echo $i;done
web-us-0
web-us-1
web-us-2
web-us-3
web-ca-0
web-ca-1
web-ca-2
web-ca-3
En caso de que los nombres de su servidor no sean fáciles de iterar, puede proporcionar una lista de nombres a for
bucle:
$ cat somelist
first_item
middle_things
foo
bar
baz
last_item
$ for i in `cat somelist`;do echo "ITEM: $i";done
ITEM: first_item
ITEM: middle_things
ITEM: foo
ITEM: bar
ITEM: baz
ITEM: last_item
Anidación
También puede combinar algunas de estas ideas para casos de uso más complejos. Por ejemplo, imagina que quieres copiar una lista de archivos a tus servidores web que siguen la convención de nomenclatura numerada que usaste en el ejemplo anterior.
Puede lograrlo iterando una segunda lista basada en su primera lista a través de bucles anidados. Esto se vuelve un poco difícil de seguir cuando lo haces de una sola línea, pero definitivamente se puede hacer. Tu for
anidado el bucle se ejecuta en cada iteración del padre for
círculo. Asegúrese de especificar diferentes nombres de variables para cada bucle.
Para copiar la lista de archivos archivo1.txt, archivo2.txt, y archivo3.txt a los servidores web, use este bucle anidado:
$ for i in file{1..3};do for x in web{0..3};do echo "Copying $i to server $x"; scp $i $x; done; done
Copying file1 to server web0
Copying file1 to server web1
Copying file1 to server web2
Copying file1 to server web3
Copying file2 to server web0
Copying file2 to server web1
Copying file2 to server web2
Copying file2 to server web3
Copying file3 to server web0
Copying file3 to server web1
Copying file3 to server web2
Copying file3 to server web3
Cambio de nombre más creativo
Puede haber otras formas de hacer esto, pero recuerda, este es solo un ejemplo de las cosas que puedes hacer con un for
círculo. ¿Qué sucede si tiene una montaña de archivos con un nombre similar a FILE002.txt? y desea reemplazar FILE con algo como TEXTO . Recuerda que además del propio Bash, también tienes a tu disposición otras herramientas de código abierto, como sed
, grep
, y más. Puede combinar esas herramientas con for
bucle, así:
$ ls FILE*.txt
FILE0.txt FILE10.txt FILE1.txt FILE2.txt FILE3.txt FILE4.txt FILE5.txt FILE6.txt FILE7.txt FILE8.txt FILE9.txt
$ for i in $(ls FILE*.txt);do mv $i `echo $i | sed s/FILE/TEXT/`;done
$ ls FILE*.txt
ls: cannot access 'FILE*.txt': No such file or directory
$ ls TEXT*.txt
TEXT0.txt TEXT10.txt TEXT1.txt TEXT2.txt TEXT3.txt TEXT4.txt TEXT5.txt TEXT6.txt TEXT7.txt TEXT8.txt TEXT9.txt
Agregar un bucle for a un script Bash
Ejecutando for
Los bucles directamente en la línea de comandos son excelentes y le ahorran una cantidad considerable de tiempo para algunas tareas. Además, puede incluir for
bucles como parte de sus scripts de Bash para aumentar la potencia, la legibilidad y la flexibilidad.
Por ejemplo, puede agregar el ejemplo de bucle anidado a un script de Bash para mejorar su legibilidad, así:
$ vim copy_web_files.sh
# !/bin/bash
for i in file{1..3};do
for x in web{0..3};do
echo "Copying $i to server $x"
scp $i $x
done
done
Cuando guarda y ejecuta este script, el resultado es el mismo que ejecutar el ejemplo de bucle anidado anterior, pero es más legible, además es más fácil de cambiar y mantener.
$ bash copy_web_files.sh
Copying file1 to server web0
Copying file1 to server web1
... TRUNCATED ...
Copying file3 to server web3
También puede aumentar la flexibilidad y la reutilización de su for
bucles incluyéndolos en los scripts de Bash que permiten la entrada de parámetros. Por ejemplo, para cambiar el nombre de archivos como el ejemplo Renombramiento más creativo anterior que permite al usuario especificar el sufijo del nombre, use este script:
$ vim rename_files.sh
# !/bin/bash
source_prefix=$1
suffix=$2
destination_prefix=$3
for i in $(ls ${source_prefix}*.${suffix});do
mv $i $(echo $i | sed s/${source_prefix}/${destination_prefix}/)
done
En este script, el usuario proporciona el prefijo del archivo de origen como primer parámetro, el sufijo del archivo como segundo y el nuevo prefijo como tercer parámetro. Por ejemplo, para cambiar el nombre de todos los archivos que comienzan con FILE , de tipo .txt a TEXTO , ejecute el script así:
$ ls FILE*.txt
FILE0.txt FILE10.txt FILE1.txt FILE2.txt FILE3.txt FILE4.txt FILE5.txt FILE6.txt FILE7.txt FILE8.txt FILE9.txt
$ bash rename_files.sh FILE txt TEXT
$ ls TEXT*.txt
TEXT0.txt TEXT10.txt TEXT1.txt TEXT2.txt TEXT3.txt TEXT4.txt TEXT5.txt TEXT6.txt TEXT7.txt TEXT8.txt TEXT9.txt
Esto es similar al ejemplo original, pero ahora sus usuarios pueden especificar otros parámetros para cambiar el comportamiento del script. Por ejemplo, para cambiar el nombre de todos los archivos que ahora comienzan con TEXT a NUEVO , utilice lo siguiente:
$ bash rename_files.sh TEXT txt NEW
$ ls NEW*.txt
NEW0.txt NEW10.txt NEW1.txt NEW2.txt NEW3.txt NEW4.txt NEW5.txt NEW6.txt NEW7.txt NEW8.txt NEW9.txt
[ Un curso gratuito para usted:Resumen técnico de virtualización y migración de infraestructura. ]
Conclusión
Con suerte, estos ejemplos han demostrado el poder de un for
bucle en la línea de comandos de Bash. Realmente puede ahorrar mucho tiempo y realizar tareas de una manera menos propensa a errores con bucles. Sólo sé cuidadoso. Tus bucles harán lo que les pidas, incluso si les pides que hagan algo destructivo por accidente, como crear (o eliminar) volúmenes lógicos o discos virtuales.
Esperamos que Bash for
los bucles cambian tu mundo de la misma manera que cambiaron el nuestro.