Este es uno de los capítulos del tutorial PowerShell. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.
Hasta el momento todo lo que hemos hecho con PowerShell, ha sido en una sola línea. Cierto es que en ocasiones has encadenado varias operaciones mediante tuberías o pipes, pero nunca has ido mucho mas lejos de esto. Sin embargo, tarde o temprano, vas a querer hacer operaciones mas complejas. Es mas, tarde o temprano, vas a querer hacer scripts para exprimir al máximo el potencial que te ofrece PowerShell. Así, en los próximos capítulos de este tutorial entraremos en el fantástico mundo de los scripts, y para empezar en este capítulo en concreto vas a abordar los bucles en PowerShell.
Los bucles en PowerShell, al igual que en otros lenguajes, tienen un gran potencial y son realmente super útiles y altamente productivos, porque te van a evitar repetir una determinada operación una y otra vez repitiendo el mismo código. Pero, no quiero adelantarme. Vamos a por los bucles en PowerShell.
Bucles en PowerShell
¿Que es un bucle?
Un bucle es una herramienta que te permite repetir una misma operación u operaciones, un número de veces, o incluso repetir de forma indefinida.
Existen diferentes tipos de bucles, e incluso cmdlet que te van a permitir repetir una y otra vez una determinada operación. Pero no solo se trata de repetir. En ocasiones quieres realizar operaciones sobre todos los elementos de un conjunto, esto es carne de cañón de los bucles. Por ejemplo, imagina que quieres dar un determinado permiso a todos los usuarios de un grupo, esto lo puedes hacer, de forma muy sencilla con un bucle.
Para los ejemplos que vendrán a continuación, utilizaremos el cmdlet, Get-Process
, que te devolverá todos los procesos que se encuentran corriendo en tu sistema. Y algunos de los conceptos que ya viste en el capítulo anterior que trataba sobre variables en PowerShell.
El bucle for
Este tipo de bucle te permite iterar en un rango de números, recorriendo este rango de números de forma creciente o decreciente, hasta cumplir una determinada condición.
Esta estructura, sin lugar a dudas le habría venido fantásticamente a Bart Simpson,
Por ejemplo, volviendo sobre el caso del cmdlet, Get-Process
, si quieres conocer el nombre de cada uno de los procesos que están corriendo en tu sistema, lo podrías hacer entre otras formas de la siguiente,
$ps = Get-Process
for($i=0; $i -lt $ps.Length; $i++){
Write-Output $ps[$i].Name
}
En lugar de hacerlo creciente también lo podrías haber hecho decreciente de la siguiente forma,
$ps = Get-Process
for($i=ps.Length-1; $i -gt 0; $i--){
Write-Output $ps[$i].Name
}
Y además no es necesario que pases por cada uno de los procesos, es decir, podrías obtener solo uno de cada cinco procesos, como puedes ver en el siguiente ejemplo,
$ps = Get-Process
for($i=0;$i -lt $ps.Length; $i=$i+5){
Write-Output $ps[$i].Name
}
Los bucles do-until
y do-while
Estas dos estructuras de control te permiten repetir diferentes operaciones hasta que se cumpla una condición, o por el contrario, mientras se cumpla una condición. Por ejemplo, para el caso do-until
,
PS> $valor = 0
PS> do{
>> $valor += 1
>> Write-Ouput $valor
>> }until($valor -gt 1)
1
2
Mientras que para el caso do-while
, esto mismo lo podrías hacer de la siguiente forma,
PS> $valor = 0
PS> do{
>> $valor += 1
>> Write-Ouput $valor
>> }while($valor -lt 2)
1
2
While
Otro clásico de los clásicos entre las estructuras que te permiten hacer bucles es while
. Este es muy similar a los que hemos visto anteriormente, pero donde el condicional está antes de comenzar el bucle. De esta forma, mientras que con do-while
, siempre ejecutamos el contenido del bucle al menos una vez antes de realizar la comprobación de la condición, en el caso de while
, se tiene que cumplir la condición. Por ejemplo,
PS> $valor = 0
PS> while($valor -lt 2){
>> $valor += 1
>> Write-Output $valor
}
1
2
break, continue y return
Pero, sin lugar a dudas, tres de los grandes olvidados, al menos para mi, de esto de los bucles son sin lugar a dudas break
, continue
y return
. Estos elementos, que inicialmente pueden no parecerte interesantes, no te equivoques, son realmente productivos, y en un momento pueden mejorar sensiblemente tus scripts.
El primero de estos tres elementos es break
. Este elemento te permite detener el bucle en cualquier momento. Por ejemplo, en el caso de un bucle a través de un array, es una interesante solución para salir del bucle en el momento en el que localizas el elemento que estás buscando. Por ejemplo,
PS> $array = 1..10000
PS> for($i=0;$i -lt $array.Length;i++){
>> if($array[$i] -eq 2){
>> break
>> }
>> }
0
1
2
Lo cierto es que break
te ayuda a optimizar sensiblemente tu código en el sentido de que te evita continuar iterando sobre todo el bucle en el momento que ya has encontrado el elemento que andabas buscando.
El siguiente de estos elementos es continue
. Este te permite saltarte unos pasos del bucle cuando se cumple una condición, o simplemente cuando se encuentra esta instrucción en el mismo bucle. Por ejemplo, si quieres imprimir números pares, puedes hacerlo de la siguiente forma,
PS> $array = 1..1000
>> for($i=0;$i -lt $array.Length;$i++){
>> if($array[$i]%2 -ne 0){
>> continue
>> }
>> Write-Output $array[$i]
>> }
En el caso del ejemplo anterior cuando se cumple la condición cuando el resto de la operación es distinto de cero, y en ese caso salta el resto de instrucciones que se encuentren a continuación.
Por último la instrucción return
hace algo similar a break
, pero además devuelve el resultado que le hayamos indicado, si es que le hemos indicado alguno. Por ejemplo,
PS> $array = 1..10000
PS> for($i=0;$i -lt $array.Length;i++){
>> if($array[$i] -eq 2){
>> return $array[$i]
>> }
>> }
2
ForEach
Por último, no quiero dejarme a ForEach
. Aunque esto no es estrictamente una estructura, en el sentido de que es un método de determinados objetos, como por ejemplo los array. Sin embargo, es indudable, que este método te va a permitir recorrer todos los elementos del array. Un ejemplo, de un ForEach
en un array es el siguiente,
PS> $array.ForEach({Write-Output $_})
Que es totalmente equivalente a la que hemos visto anteriormente,
PS> $array.ForEach({Write-Output $PSItem})
Es decir, básicamente $_
y $PSItem
representan igualmente cada uno de los elementos del array, en este caso, o de los elementos del objeto que estas tratando.
Conclusión
Ahora ya no tienes excusa para comportarte como Bart Simpson. Con las herramientas que has visto en este capítulo del tutorial, puedes iterar sobre los elementos de un array, o repetir determinadas instrucciones tantas veces como necesites, o incluso de manera indefinida.