Laços for e foreach
Esta aula aborda os laços for e foreach em PowerShell, explicando suas sintaxes, usos e diferenças em relação ao cmdlet ForEach-Object. Inclui exemplos práticos e exercícios para fixação.
Laços de repetição são fundamentais em qualquer linguagem de programação, permitindo executar um bloco de código múltiplas vezes. Em PowerShell, temos diversas construções para iteração, sendo for e foreach duas das mais comuns. Nesta aula, vamos explorar cada uma delas em detalhes, entender suas particularidades e aprender quando usar cada uma.
O laço for é ideal quando você precisa controlar explicitamente o número de iterações, geralmente com uma variável contadora. Já o foreach é mais intuitivo para percorrer coleções de objetos, como arrays ou listas, sem se preocupar com índices. Além disso, veremos a diferença entre o statement foreach e o cmdlet ForEach-Object, que são frequentemente confundidos.
for
O laço for executa um bloco de código enquanto uma condição for verdadeira. Sua sintaxe é composta por três partes: inicialização, condição e incremento/decremento. A inicialização ocorre uma vez no início; a condição é avaliada antes de cada iteração; e o incremento é executado ao final de cada iteração.
Sintaxe básica:
for (<inicialização>; <condição>; <incremento>)
{
<bloco de comando>
}Exemplo: exibir números de 1 a 5.
for ($i = 1; $i -le 5; $i++)
{
Write-Host "Número: $i"
}Você pode usar o for para percorrer arrays usando índices:
$frutas = @("maçã", "banana", "laranja")
for ($i = 0; $i -lt $frutas.Length; $i++)
{
Write-Host "Fruta $i: $($frutas[$i])"
}Também é possível criar loops infinitos (embora não recomendado) omitindo a condição:
for (;;) { Write-Host "Loop infinito" }foreach (statement)
O foreach statement é uma construção de linguagem que itera sobre cada elemento de uma coleção (como um array ou uma lista). Sua sintaxe é mais simples que o for, pois não requer variável de índice.
Sintaxe:
foreach (<variável> in <coleção>)
{
<bloco de comando>
}Exemplo com array:
$frutas = @("maçã", "banana", "laranja")
foreach ($fruta in $frutas)
{
Write-Host "Fruta: $fruta"
}O foreach pode ser usado com qualquer objeto que implemente a interface IEnumerable, como resultados de cmdlets:
foreach ($processo in Get-Process)
{
Write-Host "Processo: $($processo.Name)"
}Importante: o foreach statement carrega toda a coleção na memória antes de iterar, o que pode ser problemático com coleções muito grandes. Nesses casos, considere usar o pipeline com ForEach-Object.
Diferença para ForEach-Object
O cmdlet ForEach-Object (aliases: foreach, %) é usado no pipeline para processar objetos um de cada vez, sem carregar toda a coleção na memória. Ele é mais eficiente para grandes volumes de dados e permite encadeamento com outros cmdlets.
Sintaxe:
<coleção> | ForEach-Object { <bloco de comando> }Dentro do bloco, o objeto atual é representado por $_ ou $PSItem.
Exemplo:
1..5 | ForEach-Object { Write-Host "Número: $_" }Principais diferenças:
- Memória:
foreachstatement carrega toda a coleção na memória;ForEach-Objectprocessa um item por vez. - Pipeline:
ForEach-Objectse integra perfeitamente ao pipeline;foreachstatement não. - Desempenho:
foreaché geralmente mais rápido para coleções pequenas e médias;ForEach-Objecttem overhead de pipeline. - Uso:
foreaché mais legível para scripts simples;ForEach-Objecté preferido em expressões no pipeline.
Exemplo comparativo: somar números de 1 a 1000.
Com foreach:
$soma = 0
foreach ($n in 1..1000) { $soma += $n }
Write-Host "Soma: $soma"Com ForEach-Object:
$soma = 0
1..1000 | ForEach-Object { $soma += $_ }
Write-Host "Soma: $soma"Ambos produzem o mesmo resultado, mas o foreach tende a ser mais rápido.
Exemplos
Vamos ver alguns exemplos práticos que combinam os conceitos.
Exemplo 1: Percorrer um array de números e exibir apenas os pares.
$numeros = 1..10
foreach ($num in $numeros)
{
if ($num % 2 -eq 0)
{
Write-Host "$num é par"
}
}Exemplo 2: Usar for para criar uma tabuada de multiplicação.
$numero = 7
for ($i = 1; $i -le 10; $i++)
{
Write-Host "$numero x $i = $($numero * $i)"
}Exemplo 3: Processar arquivos em um diretório com ForEach-Object.
Get-ChildItem -Path C:\Temp -File | ForEach-Object {
Write-Host "Arquivo: $($_.Name), Tamanho: $($_.Length) bytes"
}Exemplo 4: Uso de break e continue dentro de foreach.
$numeros = 1..10
foreach ($n in $numeros)
{
if ($n -eq 5) { continue } # pula o 5
if ($n -eq 8) { break } # para no 8
Write-Host $n
}
# Saída: 1 2 3 4 6 7Exemplo 5: Aninhamento de loops for para matriz bidimensional.
for ($i = 0; $i -lt 3; $i++)
{
for ($j = 0; $j -lt 3; $j++)
{
Write-Host "Posição [$i][$j]"
}
}Boas Práticas
- Prefira
foreachstatement quando a coleção for pequena e você precisar de máxima legibilidade. - Use
ForEach-Objectquando estiver trabalhando com pipelines ou coleções muito grandes. - Evite modificar a coleção dentro do loop (ex.: adicionar ou remover itens) pois pode causar comportamentos inesperados.
- Utilize
breakpara sair mais cedo econtinuepara pular iterações quando necessário.
Referências
- about_For - PowerShell | Microsoft Docs
- about_Foreach - PowerShell | Microsoft Docs
- ForEach-Object (Microsoft.PowerShell.Core) - PowerShell | Microsoft Docs
- Everything you wanted to know about arrays - PowerShell | Microsoft Docs
- Everything you wanted to know about foreach - PowerShell | Microsoft Docs
- For - PowerShell - SS64.com
- ForEach - PowerShell - SS64.com
Exercícios
Escreva um script que use o laço
forpara exibir os números ímpares de 1 a 20.✓ Resposta:for ($i = 1; $i -le 20; $i += 2) { Write-Host $i }Dado o array
$cores = @("vermelho", "azul", "verde", "amarelo"), use oforeachstatement para exibir cada cor em letras maiúsculas.✓ Resposta:$cores = @("vermelho", "azul", "verde", "amarelo") foreach ($cor in $cores) { Write-Host $cor.ToUpper() }Use
ForEach-Objectpara exibir o nome de cada processo em execução que tenha mais de 10 MB de memória (WorkingSet). Dica:Get-Processretorna objetos com a propriedadeWorkingSet(em bytes). Converta para MB.✓ Resposta:Get-Process | ForEach-Object { if ($_.WorkingSet -gt 10MB) { Write-Host $_.Name } }Crie um script que, usando o laço
for, calcule a soma dos números de 1 a 100 e exiba o resultado.✓ Resposta:$soma = 0 for ($i = 1; $i -le 100; $i++) { $soma += $i } Write-Host "Soma: $soma"Escreva um script que use
foreachpara percorrer os arquivos emC:\Windows\System32(apenas arquivos, não pastas) e exiba o nome e o tamanho em KB daqueles que têm tamanho maior que 50 KB.✓ Resposta:$arquivos = Get-ChildItem -Path C:\Windows\System32 -File foreach ($arquivo in $arquivos) { $tamanhoKB = $arquivo.Length / 1KB if ($tamanhoKB -gt 50) { Write-Host "$($arquivo.Name) - $([math]::Round($tamanhoKB, 2)) KB" } }