TEMA
about_Foreach
DESCRIPCIÓN BREVE
Describe un comando de lenguaje que se puede utilizar para
recorrer todos los elementos de una colección de elementos.
DESCRIPCIÓN DETALLADA
La instrucción Foreach (también denominada bucle Foreach) es una
construcción de lenguaje para recorrer paso a paso (en iteración) una
serie de valores de una colección de elementos.
El tipo de colección más sencillo y típico para recorrer es una matriz.
En un bucle Foreach, es habitual ejecutar uno o varios comandos
respecto a cada elemento de una matriz.
Sintaxis
A continuación se muestra la sintaxis de la instrucción Foreach:
foreach ($<elemento> in $<colección>){<lista de instrucciones>}
Instrucción Foreach fuera de una canalización de comando
La parte de la instrucción Foreach incluida entre paréntesis
representa una variable y una colección que se recorrerá en
iteración. Windows PowerShell crea la variable ($<elemento>)
automáticamente cuando se ejecuta el bucle Foreach. Antes de cada
iteración en el bucle, la variable se establece en un valor de la
colección. El bloque que sigue a la instrucción Foreach
{<lista de instrucciones>} contiene una colección de comandos que
se ejecutan respecto a cada elemento de una colección.
Ejemplos
Por ejemplo, el bucle Foreach del siguiente ejemplo muestra los
valores de la matriz $letterArray.
$letterArray = "a","b","c","d"
foreach ($letter in $letterArray)
{
Write-Host $letter
}
En este ejemplo, la matriz $letterArray se crea e inicializa con los
valores de cadena "a", "b", "c" y "d". La primera vez que se ejecuta la
instrucción Foreach, establece la variable $letter en el valor del primer
elemento de $letterArray ("a"). A continuación, utiliza el cmdlet
Write-Host para mostrar la letra a. La siguiente vez que se recorre
el bucle, $letter se establece en "b", y así sucesivamente. Después
de que el bucle Foreach muestre la letra d, Windows PowerShell cierra
el bucle.
La instrucción Foreach completa debe aparecer en una sola línea
para que se ejecute como un comando en el símbolo del sistema
de Windows PowerShell. En cambio, la instrucción Foreach
completa no tiene que aparecer en una única línea si el comando
se incluye en un archivo de script .ps1.
Pueden usarse también instrucciones Foreach junto con cmdlets que
devuelvan una colección de elementos. En el siguiente ejemplo, la
instrucción Foreach recorre la lista de elementos devuelta por el
cmdlet Get-ChildItem.
foreach ($file in Get-ChildItem)
{
Write-Host $file
}
El ejemplo se puede perfeccionar usando una instrucción If para
limitar los resultados que se devuelven. En el siguiente ejemplo, la
instrucción Foreach realiza la misma operación de bucle que en el ejemplo
anterior, pero se agrega una instrucción If para limitar los
resultados a los archivos con un tamaño superior a 100 kilobytes (KB):
foreach ($file in Get-ChildItem)
{
if ($file.length -gt 100k)
{
Write-Host $file
}
}
En este ejemplo, el bucle Foreach usa una propiedad de la
variable $file para realizar una operación de comparación
($file.length -gt 100k). La variable $file contiene todas las
propiedades del objeto devuelto por el cmdlet Get-ChildItem. En
consecuencia, puede devolverse más información, sin limitarse al
nombre del archivo. En el ejemplo siguiente, Windows PowerShell
devuelve la longitud y la hora del último acceso en la lista de
instrucciones:
foreach ($file in Get-ChildItem)
{
if ($file.length -gt 100k)
{
Write-Host $file
Write-Host $file.length
Write-Host $file.lastaccesstime
}
}
En este ejemplo, no hay que limitarse a ejecutar un solo
comando en una lista de instrucciones.
También se puede usar una variable fuera de un bucle Foreach e
incrementarla dentro del bucle. En el ejemplo siguiente se cuentan
los archivos cuyo tamaño es superior a 100 KB:
$i = 0
foreach ($file in Get-ChildItem)
{
if ($file.length -gt 100k)
{
Write-Host $file "tamaño de archivo:" ($file.length /
1024).ToString("F0") KB
$i = $i + 1
}
}
if ($i -ne 0)
{
Write-Host
Write-Host $i " archivo(s) con más de 100 KB en el
directorio actual."}
else
{
Write-Host "No hay ningún archivo de más de 100 KB en el
directorio actual."
}
En el ejemplo anterior, la variable $i se establece en 0 fuera
del bucle y se incrementa dentro del bucle por cada archivo
encontrado cuyo tamaño es superior a 100 KB. Cuando el bucle se
cierra, una instrucción If evalúa el valor de $i para mostrar
el recuento de todos los archivos que tienen más de 100 KB. O bien,
muestra un mensaje que afirma que no se encontró ningún archivo que
tuviera más de 100 KB.
En el ejemplo anterior también se muestra cómo dar formato a los
resultados de longitud de archivos:
($file.length / 1024).ToString("F0")
El valor se divide entre 1.024 para mostrar los resultados en
kilobytes y no en bytes, y después se aplica formato al valor
resultante mediante el especificador de formato de punto fijo
para quitar los valores decimales del resultado. El 0 hace que el
especificador del formato no muestre ninguna posición decimal.
Instrucción Foreach dentro de una canalización de comando
Cuando Foreach aparece en una canalización de comandos, Windows
PowerShell utiliza el alias de foreach, que llama al comando ForEach-Object.
Cuando se usa el alias foreach en una canalización de comandos, no se
incluye la sintaxis ($<elemento> in $<colección>) como en la
instrucción Foreach. Esto es debido a que el comando anterior de la
canalización proporciona esta información. La sintaxis del alias
foreach cuando se utiliza en una canalización de comandos es la siguiente:
<comando> | foreach {<bloqueComandos>}
Por ejemplo, el bucle Foreach incluido en la siguiente
canalización de comandos muestra los procesos cuyo espacio de
trabajo (uso de memoria) es superior a 20 megabytes (MB). Windows
PowerShell canaliza el resultado del comando Get-Process al alias foreach.
Dentro del bloque de comandos del alias foreach, la variable $_.WS
contiene el valor de la propiedad WS (conjunto de trabajo) que le ha
pasado el cmdlet Get-Process. (La sección $_ de la declaración es una
variable automática de Windows Script Host [WSH] y la sección WS es una
propiedad). La instrucción If usa una instrucción condicional para
determinar si el espacio de trabajo es superior a 20 MB (20.000.000
bytes). En caso afirmativo, se muestran el nombre del proceso
(almacenado en la variable $_.name) y el tamaño del espacio de trabajo
en megabytes.No se mostrará nada si ninguno de los espacios de trabajo de
los procesos es superior a 20 MB.
Write-Host "Procesos con espacios de trabajo mayores que 20 MB"
Get-Process | foreach {
if ($_.WS -gt 20m)
{
Write-Host $_.name ": "
($_.WS/1m).ToString("F0") MB -Separator ""
}
}
El alias foreach también admite los bloques de comandos
iniciales, en el centro y al final. Los bloques de comandos
inicial y final se ejecutan una vez, mientras que el bloque de
comandos central se ejecuta cada vez que el bucle Foreach
recorre una colección o una matriz.
La sintaxis del alias foreach en una canalización de comandos con un
conjunto de bloques de comandos inicial, central y final es la siguiente:
<comando> | foreach {<bloqueComandos inicial>}{<bloqueComandos
central>}{<bloqueComandos final>}
En el siguiente ejemplo se muestra el uso de los bloques de comandos
inicial, central y final.
Get-ChildItem | foreach {
$fileCount = $directoryCount = 0}{
if ($_.PsIsContainer) {$directoryCount++} else
{$fileCount++}}{ "$directoryCount directorios y $fileCount archivos"}
El bloque de comandos inicial crea e inicializa dos variables en 0:
{$fileCount = $directoryCount = 0}
El bloque central evalúa si cada elemento devuelto por
Get-ChildItem es un directorio o un archivo:
{if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}
Si el elemento que se devuelve es un directorio, se incrementa
en 1 la variable $directoryCount. Si el elemento no es un
directorio, se incrementa en 1 la variable $fileCount. El
bloque final se ejecuta cuando el bloque central completa su
operación de bucle y, a continuación, devuelve los resultados de la
operación:
{"$directoryCount directorios y $fileCount archivos"}
Con la estructura de bloques de comandos inicial, central y
final y el operador de canalización, puede volver a escribir el
ejemplo anterior a fin de buscar los archivos con un tamaño
superior a 100 KB, como se muestra a continuación:
Get-ChildItem | foreach{
$i = 0}{
if ($_.length -gt 100k)
{
Write-Host $_.name "tamaño del archivo:" ($_.length /
1024).ToString("F0") KB
$i++
}
}{
if ($i -ne 0)
{
Write-Host
Write-Host "$i archivo(s) con más de 100 KB en el
directorio actual."
}
else
{
Write-Host "No hay ningún archivo de más de 100 KB en el
directorio actual."}
}
VEA TAMBIÉN
about_Automatic_Variables
about_If
Foreach-Object