PowerShell para quem vem do Bash: equivalências práticas

1. Paradigmas e Filosofia de Comando

A diferença fundamental entre PowerShell e Bash está na natureza dos dados que fluem pelo pipeline. Enquanto o Bash manipula texto puro, o PowerShell trabalha com objetos .NET. Isso significa que, no Bash, você extrai informações de saídas textuais com grep, awk e sed; no PowerShell, você acessa propriedades diretamente.

Cmdlets vs. comandos Unix: PowerShell adota a estrutura Verbo-Substantivo. O comando ps do Unix equivale a Get-Process. A vantagem é que Get-Process retorna objetos com propriedades como Name, Id, CPU, que você pode acessar com pontos:

# Bash
ps aux | grep firefox

# PowerShell
Get-Process -Name firefox | Select-Object Name, CPU

Aliases e atalhos: PowerShell fornece aliases para facilitar a transição. ls, cat, rm, cp, mv funcionam, mas com comportamento sutilmente diferente. Por exemplo, ls no PowerShell é alias para Get-ChildItem e aceita parâmetros como -Recurse e -Filter.

2. Navegação e Manipulação de Arquivos

Listar diretórios: Get-ChildItem (alias ls, dir) oferece filtragem avançada:

# Bash: ls -la *.txt
# PowerShell:
Get-ChildItem -Filter *.txt | Format-Table Name, Length, LastWriteTime

Criar, copiar, mover e remover: Os cmdlets seguem o padrão Verbo-Item:

# Criar diretório
New-Item -ItemType Directory -Path C:\Temp\projeto

# Copiar arquivo
Copy-Item -Path arquivo.txt -Destination backup\ -Recurse

# Mover e renomear
Move-Item -Path relatorio.csv -Destination arquivos\relatorio_2024.csv

# Remover com confirmação
Remove-Item -Path temp\* -Recurse -Confirm

Caminhos e diretórios: Get-Location (pwd), Set-Location (cd), Split-Path (dirname):

# Bash: pwd; cd /var/log; dirname /var/log/syslog
# PowerShell:
Get-Location
Set-Location C:\Windows\System32
Split-Path -Parent "C:\Windows\System32\notepad.exe"

3. Filtragem, Seleção e Ordenação

Where-Object substitui grep e awk no pipeline de objetos:

# Bash: ps aux | grep chrome
# PowerShell:
Get-Process | Where-Object { $_.ProcessName -like "*chrome*" }

# Filtro por condição composta
Get-Process | Where-Object { $_.CPU -gt 10 -and $_.WorkingSet -gt 100MB }

Select-Object equivale a cut e awk '{print $1}':

# Bash: ps aux | awk '{print $2, $11}'
# PowerShell:
Get-Process | Select-Object Id, ProcessName, @{Name="Memória(MB)"; Expression={[math]::Round($_.WorkingSet/1MB,2)}}

Sort-Object substitui sort e uniq:

# Ordenar por uso de CPU (decrescente)
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5

# Agrupar e contar (uniq -c)
Get-Service | Group-Object Status | Select-Object Name, Count

4. Trabalhando com Texto e Strings

Operadores de comparação: -match (regex), -like (curinga), -contains (coleções):

# Bash: grep "^ERROR" log.txt
# PowerShell:
Get-Content log.txt | Where-Object { $_ -match "^ERROR" }

# Verificar se string contém padrão
if ("arquivo.txt" -like "*.txt") { Write-Output "É um arquivo texto" }

Substituição e formatação: -replace (regex), -split, -join:

# Bash: sed 's/antigo/novo/g' arquivo.txt
# PowerShell:
(Get-Content arquivo.txt) -replace "antigo", "novo" | Set-Content arquivo.txt

# Dividir string e unir com delimitador personalizado
$linha = "nome,idade,cidade"
$partes = $linha -split ","
$partes -join " | "

Leitura e escrita em arquivos: Get-Content, Set-Content, Add-Content:

# Bash: cat arquivo.txt; echo "linha" > arquivo.txt; echo "linha" >> arquivo.txt
# PowerShell:
Get-Content arquivo.txt
"texto" | Set-Content arquivo.txt   # sobrescreve
"texto" | Add-Content arquivo.txt   # anexa

5. Estruturas de Controle e Scripting

Condicionais e loops: sintaxe similar a linguagens C-like:

# Bash: for i in ${array[@]}; do echo $i; done
# PowerShell:
$servidores = @("web01", "db01", "app01")
foreach ($servidor in $servidores) {
    if (Test-Connection -ComputerName $servidor -Count 1 -Quiet) {
        Write-Output "$servidor está online"
    } else {
        Write-Warning "$servidor offline"
    }
}

Funções e escopo: uso de param() para parâmetros tipados:

function Get-DiskUsage {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Caminho,

        [ValidateSet("KB","MB","GB")]
        [string]$Unidade = "MB"
    )

    $itens = Get-ChildItem -Path $Caminho -Recurse -File
    $total = ($itens | Measure-Object -Property Length -Sum).Sum

    switch ($Unidade) {
        "KB" { $total / 1KB }
        "MB" { $total / 1MB }
        "GB" { $total / 1GB }
    }
}

Tratamento de erros: try/catch/finally substitui set -e e ||:

try {
    Get-Content "caminho\inexistente.txt" -ErrorAction Stop
} catch [System.IO.FileNotFoundException] {
    Write-Error "Arquivo não encontrado: $_"
} catch {
    Write-Error "Erro desconhecido: $_"
} finally {
    Write-Output "Execução concluída"
}

6. Gerenciamento de Processos e Serviços

Listar e encerrar processos: cmdlets nativos com objetos:

# Bash: ps aux --sort=-%mem | head -5; kill -9 1234
# PowerShell:
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5
Stop-Process -Name notepad -Force

Gerenciar serviços: Get-Service, Start-Service, Restart-Service:

# Bash: systemctl status nginx; systemctl restart nginx
# PowerShell:
Get-Service -Name Spooler | Select-Object Name, Status, StartType
Restart-Service -Name Spooler -PassThru

Monitoramento e logs: Get-EventLog (logs clássicos) e Get-WinEvent (logs modernos):

# Bash: journalctl -u sshd --since "1 hour ago"
# PowerShell:
Get-WinEvent -LogName System -MaxEvents 10 | Where-Object { $_.LevelDisplayName -eq "Error" }

7. Automação com Pipeline e Expressões

Pipeline avançado: encadeamento de cmdlets com ForEach-Object:

Get-Service | Where-Object Status -eq "Stopped" | ForEach-Object {
    Write-Output "Iniciando serviço: $($_.DisplayName)"
    Start-Service -Name $_.Name
}

Expressões calculadas: criar propriedades customizadas com @{Name=; Expression=}:

Get-Process | Select-Object Name, Id, @{
    Name = "Memória(MB)"
    Expression = { [math]::Round($_.WorkingSet/1MB, 2) }
}, @{
    Name = "Tempo(Minutos)"
    Expression = { [math]::Round($_.TotalProcessorTime.TotalMinutes, 2) }
}

Exportação de dados: Export-Csv, ConvertTo-Json, Out-File:

# Exportar processos para CSV
Get-Process | Select-Object Name, CPU, WorkingSet | Export-Csv -Path processos.csv -NoTypeInformation

# Converter para JSON
Get-Service | Where-Object Status -eq "Running" | ConvertTo-Json | Out-File servicos.json

# Formatar saída em tabela
Get-Process | Format-Table -AutoSize -Wrap

Referências