Pipelines I: PowerShell declarativo
Abstract
Pensar en pasos: de colecciones al pipeline de PowerShell
Antes de hablar del pipeline de PowerShell, pensemos en una idea más simple: procesar una colección paso a paso.
En muchos lenguajes, cuando tienes una colección de datos, aplicas una secuencia de operaciones: filtrar, transformar, eliminar duplicados, limitar resultados. Cada paso toma el resultado del anterior.
Transformaciones encadenadas
Una transformación recibe una colección de entrada y produce otra colección de salida. Al encadenarlas, describes qué quieres hacer con los datos, no cómo recorrerlos elemento por elemento.
El mismo problema, expresado como pasos
users
.filter(_.active)
.map(_.email)
.distinct
.take(10)list(
islice(
dict.fromkeys(
map(
lambda u: u.email,
filter(lambda u: u.active, users)
)
),
10
)
)SELECT DISTINCT email
FROM users
WHERE active = TRUE
LIMIT 10;Aunque la sintaxis cambia, la idea es siempre la misma:
- Quedarse solo con los elementos que cumplen una condición.
- Extraer un dato relevante de cada elemento.
- Eliminar duplicados.
- Tomar solo una cantidad limitada de resultados.
¿Dónde entra PowerShell?
El pipeline de PowerShell es otra forma de expresar exactamente esta misma idea, pero en lugar de encadenar métodos o funciones, conecta comandos.
Cada comando:
- recibe objetos como entrada,
- procesa uno a uno,
- y envía el resultado al siguiente comando.
Esa conexión se escribe con el operador |, que puedes leer como
“pasa el resultado a…”.
El mismo flujo expresado como pipeline
Import-Csv users.csv |
Where-Object { $_.active -eq 'true' } |
Select-Object -ExpandProperty email |
Sort-Object -Unique |
Select-Object -First 10 Detalles clave
-
|conecta pasos: no es “texto”, son objetos que fluyen entre comandos. - Filtrar temprano: igual que en SQL o FP, reduces trabajo en los pasos siguientes.
- Procesamiento incremental: PowerShell no necesita cargar todo en memoria para empezar a trabajar.
- La salida final decide el formato: solo al final conviertes a texto, archivo o reporte.
¿Por qué queremos una sintaxis declarativa?
Ahora que entendemos por qué el procesamiento en streaming es valioso, veamos cómo PowerShell lo aplica a su modelo de ejecución: el pipeline.
El operador de pipeline ( ) conecta comandos pasando
objetos de uno a otro. A diferencia de otros shells que encadenan texto,
PowerShell transmite instancias con propiedades
(por ejemplo, | | ), lo que permite filtrar, transformar
y exportar datos sin parseo frágil. El pipeline opera en streaming: cada objeto
se envía al siguiente comando apenas está disponible, permitiendo trabajar con grandes
volúmenes sin cargar todo en memoria.
FileInfo FileInfo
Ventajas prácticas
- Legibilidad: el flujo se lee como una historia (fuente → filtro → transformación → orden → límite → salida).
- Composición: cambias una etapa sin reescribir todo el procedimiento.
- Optimizable: filtrar temprano y cortar (
) reduce trabajo (igual que un optimizador empuja WHERE hacia abajo).-First-First - Razonable y testeable: cada etapa tiene contrato claro (entrada → salida), con menos estado mutable.
SQL como espejo
SQL funciona porque describe qué quieres y delega el cómo al motor. En pipelines buscamos el mismo beneficio: un vocabulario de transformaciones para reordenar, cortar temprano, instrumentar y componer sin ensuciar la intención.
Get-ChildItem -Path $HOME -Recurse -File |
Where-Object { $_.Length -gt 0 } |
Sort-Object Length -Descending |
Select-Object FullName, Length -First 10 |
Export-Csv "top10.csv" -NoTypeInformation Detalles clave
Este flujo recorre archivos, descarta los de longitud cero, los ordena por tamaño, toma los 10 mayores y los exporta a CSV. Observa cómo cada comando asume una responsabilidad única y clara:
-
emite objetosGet-ChildItem -Recurse -FileGet-ChildItem -Recurse -Filede forma secuencial (streaming).FileInfoFileInfo -
filtra temprano para reducir lo que fluye.Where-Object { $_.Length -gt 0 }Where-Object { $_.Length -gt 0 } -
ordena por una propiedad sin convertir a texto.Sort-Object Length -DescendingSort-Object Length -Descending -
limita el flujo tras obtener lo necesario, sin cargar todo en memoria.Select-Object ... -First 10Select-Object ... -First 10 -
materializa el resultado en formato CSV (Comma-Separated Values) en el directorio actual. Puedes ver el archivo con VSCode usandoExport-Csv "top10.csv"Export-Csv "top10.csv".code top10.csvcode top10.csv
Cuidado con cortar el pipeline demasiado pronto
Cmdlets de formato ( , Format-Table Format-Table ) producen objetos de formato, no datos reales. Si los usas en medio del
flujo, los siguientes comandos no verán las propiedades originales.
Format-List Format-List
Evita usarlos hasta el final del pipeline —prefiere o
Select-Object Select-Object si necesitas preparar la salida antes.
Out-File Out-File
Del pipeline al method chaining (Scala) y a SQL
La idea central del pipeline es la misma que en la programaci¢n funcional y en APIs de method chaining: construir un flujo como una composici¢n de pasos peque¤os. Cada paso recibe una entrada, produce una salida, y el siguiente paso decide qu‚ hacer con ella.
Lo valioso no es solo el streaming, sino la sintaxis declarativa: expresar qu‚ quieres (filtrar, proyectar, ordenar, limitar) sin escribir un bucle imperativo con variables temporales.
Por qu‚ queremos una sintaxis declarativa
- Legibilidad: el flujo se lee como una historia (fuente -> filtro -> transformaci¢n -> orden -> l¡mite -> salida).
- Composici¢n: cambias una etapa sin reescribir todo el procedimiento.
- Optimizable: filtrar temprano y cortar con
reduce trabajo (igual que un optimizador empuja WHERE hacia abajo).-First-First - Razonable y testeable: cada etapa tiene contrato claro (entrada -> salida), con menos estado mutable.
El mismo contrato en PowerShell, Scala y SQL
Tres notaciones para el mismo objetivo: "dame los 10 correos £nicos de usuarios activos".
Import-Csv users.csv |
Where-Object { $_.active -eq 'true' } |
Select-Object -ExpandProperty email |
Sort-Object -Unique |
Select-Object -First 10users
.filter(_.active)
.map(_.email)
.distinct
.take(10)SELECT DISTINCT email
FROM users
WHERE active = TRUE
LIMIT 10; Por qu‚ SQL es un gran espejo
SQL funciona porque describe qu‚ quieres y delega el c¢mo al motor (planificador/optimizador). En pipelines buscamos el mismo beneficio: un vocabulario de transformaciones para poder reordenar, cortar temprano, instrumentar y componer sin ensuciar la intenci¢n del flujo.
Ejercicio corto
Ejercicio: Traducir cadenas declarativas a PowerShell
Entrada
- Un pequeño pipeline en Python (ver arriba) que filtra, proyecta, deduplica y toma.
- Una consulta SQL SELECT DISTINCT ... WHERE ... LIMIT 10.
Piensa rápido
- Escribe el pipeline equivalente en PowerShell usando
,Where-ObjectWhere-Object,Select-ObjectSelect-ObjectySort-Object -UniqueSort-Object -Unique.Select-Object -FirstSelect-Object -First
Solución
Import-Csv users.csv |
Where-Object { $_.active -eq 'true' } |
Select-Object -ExpandProperty email |
Sort-Object -Unique |
Select-Object -First 10Conclusiones
El pipeline de PowerShell se entiende mejor como sintaxis declarativa cercana a FP, method chaining y SQL. Piensa en transformar flujos paso a paso, filtrando temprano y materializando al final.
Puntos clave
¿Qué nos llevamos?
¿Con ganas de más?
Referencias recomendadas
- “ Collection Pipeline ” en MartinFowler.comPatrón para encadenar operaciones declarativas en colecciones (filter/map/reduce), espejo útil del pipeline.