Comandos reutilizables y validación de parámetros en Nushell
Metadatos de la lección
- Autoría:
- Ignacio Slater-Muñoz
- Última actualización:
- 27 de marzo de 2026
Cambios recientes:
-
8880728· 27 de marzo de 2026 · ✨ feat(notes): add abstract slots and Python structured-output lesson ( GitLab / GitHub ) -
4aaafb3· 19 de marzo de 2026 · :sparkles: feat(nushell): restructure structured output lesson flow ( GitLab / GitHub ) -
4443cc6· 12 de marzo de 2026 · ✨♻️ feat(references): refine catalog-driven bibliography rendering ( GitLab / GitHub )
Encuentra el código de la lección:
Abstract
Esta lección muestra cómo organizar en Nushell un primer conjunto de comandos
reutilizables para generar y escribir un README.md, separando la
construcción del contenido, la validación de parámetros y la persistencia en disco.
El foco está en organizar comandos como módulos, importarlos con , definir firmas tipadas, devolver strings y escribir validaciones
explícitas cuando Nushell no ofrece un equivalente declarativo directo a los atributos
de PowerShell.
use use
Scripts ejecutables versus módulos importados con use use
use use
En la lección base distinguimos entre cmdlets, funciones y scripts. En Nushell,
para empezar, suele ser más claro pensar en comandos definidos por quien programa
dentro de archivos de módulo. Esos archivos pueden ejecutarse como scripts en otros
escenarios, pero cuando queremos reutilizar comandos entre archivos la vía principal es
exportarlos con e importarlos con export export .
use use
use use export def render-readme-heading [
name: string,
--verbose (-v)
] {
if $verbose {
print $"Preparing README heading for '($name)'"
}
$"# ($name)"
} Detalles clave
-
: define un comando en Nushell. Aquídefdefrecibe argumentos, ejecuta un bloque y produce una salida que puede seguir fluyendo por el pipeline.render-readme-headingrender-readme-heading -
: hace que el comando quede disponible para otros contextos cuando se importe el módulo conexportexport. Sinuseuse, la definición queda local al módulo.exportexport - Parámetros y flags:
es un parámetro obligatorio y tipado; la llamada debe proporcionar un valor. En cambio,name: stringname: stringes un flag opcional con nombre largo y alias corto, parecido a declarar--verbose (-v)--verbose (-v)en PowerShell.[Alias('v')] [switch] $Verbose[Alias('v')] [switch] $Verbose - Interpolación de strings: Nushell permite insertar valores dentro de texto usando la sintaxis
. Dentro de ese string, cualquier expresión entre paréntesis se evalúa e inserta en el resultado. En el ejemplo,$"..."$"..."reemplaza$"Preparing README heading for '($name)'"$"Preparing README heading for '($name)'"por el valor recibido como argumento.($name)($name) - Salida de depuración explícita: en este ejemplo usamos el patrón
para emitir mensajes adicionales solo cuando el flag está presente. A diferencia deif $verbose { print ... }if $verbose { print ... }en PowerShell, aquí no hay un canal de verbosidad equivalente activado automáticamente porWrite-VerboseWrite-Verbose; el comportamiento se modela de forma explícita en el propio comando.-Verbose-Verbose - Retorno implícito: igual que en PowerShell, no es necesario escribir una instrucción especial para devolver el resultado. La última expresión evaluada en el bloque — en este caso
— se emite como salida del comando.$"# ($name)"$"# ($name)"
Uso
use ./scaffolding/readme-heading-module.nu *
render-readme-heading "Utility Scripts - DIBS" --verbose
render-readme-heading "Utility Scripts - DIBS" | describescripts-nushell/ Detalles clave
-
: importa definiciones exportadas desde un módulouseuse.nu. En este caso importamos todas las definiciones con, pero también podríamos haber importado solo**para limitar el alcance a ese comando específico.[render-readme-heading][render-readme-heading] -
: inspecciona el tipo de la salida que recibe por pipeline. Aquí sirve para verificar quedescribedescribeproduce un valor de texto, no solo un efecto visual en pantalla.render-readme-headingrender-readme-heading
Generar el contenido inicial del README.md
Una vez que ya tenemos un comando pequeño para producir el encabezado, el siguiente paso
es reutilizarlo y componer una plantilla inicial de README.md a partir de
unos pocos parámetros.
En esta comparativa nos conviene mantener el foco en una salida simple: el comando genera texto y devuelve ese texto como resultado. La escritura a disco queda como un paso separado. Esto clarifica dónde vive cada responsabilidad.
use ./readme-heading-module.nu [render-readme-heading]
export def new-readme [
name: string
--verbose (-v)
] {
if $verbose {
print $"Creating README.md for project '($name)'"
}
let timestamp = (date now | format date "%Y-%m-%d %H:%M:%S")
let heading = if $verbose {
render-readme-heading $name --verbose
} else {
render-readme-heading $name
}
$"($heading)
Project initialized on ($timestamp).
Learn more about READMEs at https://www.makeareadme.com/.
"
} Detalles clave
-
: importa el comando exportado del módulo auxiliar para queuse ./readme-heading-module.nu [render-readme-heading]use ./readme-heading-module.nu [render-readme-heading]quede disponible y pueda reutilizarse dentro de este módulo.render-readme-headingrender-readme-heading -
: permite asignar nombres a valores intermedios. Aquí se usa para guardar la marca temporal y también el encabezado generado por el comando auxiliar.letlet -
: obtiene la fecha actual y la convierte en el formato que queremos insertar en el README.date now | format date "%Y-%m-%d %H:%M:%S"date now | format date "%Y-%m-%d %H:%M:%S" - Propagación manual del modo verboso: el bloque
muestra cómo decidir explícitamente si reenviamos o no el flag al comando auxiliar. A diferencia de PowerShell, donde la propagación puede ser automática, aquí la decisión es visible en el código.if $verbose { ... } else { ... }if $verbose { ... } else { ... } - String multilínea interpolado: la expresión final usa
para insertar$"..."$"..."y($heading)($heading)dentro del texto completo del archivo.($timestamp)($timestamp) - Retorno final: la última expresión del bloque se emite como salida del comando, así que
produce un string que luego puede inspeccionarse, transformarse o enviarse por pipeline a otro comando (comonew-readmenew-readme).savesave
Uso
Nota sobre importaciones entre módulos
readme-template-module.nu readme-template-module.nu importa
readme-heading-module.nu readme-heading-module.nu para reutilizar
render-readme-heading render-readme-heading . Luego, tu sesión interactiva
solo necesita importar readme-template-module.nu readme-template-module.nu con
use use para acceder a new-readme new-readme .
Igual que en PowerShell, conviene separar la lógica que produce datos de la
que realiza efectos como escribir archivos. Aquí, genera el contenido; luego lo guardaremos en disco en un
paso separado. Eso también hace el comando más fácil de probar: puedes verificar el
string resultante sin depender del sistema de archivos.
new-readme new-readme
use ./scaffolding/readme-template-module.nu *
new-readme "Utility Scripts - DIBS" --verbosescripts-nushell/. Validar la salida y escribir el archivo
Hasta aquí ya podemos generar el contenido del README como texto. El siguiente paso es validar el directorio de salida y luego escribir el archivo. Esta separación deja más claro qué parte del comando produce datos y cuál realiza efectos sobre el sistema de archivos.
Aquí aparece una diferencia relevante con PowerShell: Nushell admite parámetros tipados
y flags, pero no tiene un equivalente directo a validaciones declarativas por
atributos como o
[ValidateNotNullOrEmpty()][ValidateNotNullOrEmpty()]. Cuando la validación depende del
contexto, lo habitual es escribirla de forma explícita dentro del comando o en una
función auxiliar.
[ValidateScript(...)][ValidateScript(...)]
use ./readme-template-module.nu [new-readme]
def ensure-output-dir [dir: string] {
if not ($dir | path exists) {
error make {
msg: "The output directory does not exist."
}
}
if (($dir | path type) != "dir") {
error make {
msg: "The output path must be a directory."
}
}
$dir
}
export def write-readme [
name: string,
--out-dir (-o): path = "."
] {
let out_dir = ensure-output-dir $out_dir
let readme_content = new-readme $name
$readme_content | save ($out_dir | path join "README.md")
} Detalles clave
- Validación de ruta: primero se comprueba con
que la ruta exista, y luego con$dir | path exists$dir | path existsque corresponda específicamente a un directorio.$dir | path type$dir | path type -
: construye y lanza un error de forma explícita. Para este nivel basta entenderlo como la manera de abortar el comando con un mensaje claro cuando una validación falla.error makeerror make - Precondición explícita:
encapsula una regla que debe cumplirse antes de escribir el archivo: la ruta de salida debe existir y debe ser un directorio. Este patrón modela un contrato claro que el programa depende de verificar.ensure-output-dirensure-output-dir - Validación reutilizable: mover la comprobación a
evita duplicación y permite reutilizar la misma regla en otros comandos que también escriban archivos.ensure-output-dirensure-output-dir - Definición local del módulo:
no se exporta, así que funciona como helper interno. En cambio,ensure-output-dirensure-output-dirsí se exporta y constituye la API pública del módulo.write-readmewrite-readme - Validación explícita en vez de declarativa: a diferencia de PowerShell, estas reglas no se expresan mediante atributos sobre el parámetro, sino en una función auxiliar que inspecciona el valor en tiempo de ejecución.
- Efecto principal del comando: en esta etapa el objetivo ya no es producir texto para seguir transformándolo, sino persistirlo en disco. El foco del comando pasa desde el valor producido al efecto realizado.
Uso
use ./scaffolding/readme-writer-module.nu *
write-readme "Utility Scripts - DIBS"
write-readme "Utility Scripts - DIBS" --out-dir ./demoscripts-nushell/. Detalles clave
- Ejecución simple:
sin parámetrowrite-readmewrite-readmeguarda el README en el directorio actual (valor por defecto--out-dir--out-dir).".""." - Directorio personalizado: con el flag
o su alias--out-dir--out-dirpuedes especificar otro directorio donde guardar el archivo. El comando validará que ese directorio exista antes de escribir.-o-o - Validación automática: si el directorio especificado no existe o no es un directorio,
detiene la ejecución y emite un mensaje de error antes de escribir nada.write-readmewrite-readme
Conclusiones
En esta lección vimos cómo Nushell permite construir una automatización pequeña pero
bien organizada a partir de comandos reutilizables. El recorrido pasó por cargar
definiciones exportadas desde módulos con ,
componer comandos que devuelven texto, y separar con claridad la generación del
contenido de la escritura efectiva del archivo.
use use
También apareció una diferencia importante en la validación: además de las firmas tipadas, varias reglas deben expresarse como lógica explícita dentro del comando o en funciones auxiliares.
Puntos clave
-
importa definiciones exportadas desde módulosuseuse.nuy establece una forma clara de reutilización entre archivos. - Las firmas tipadas de Nushell describen parámetros y flags, pero las validaciones más específicas siguen escribiéndose como código explícito.
- Separar
denew-readmenew-readmepermite distinguir entre producir texto y realizar un efecto sobre el sistema de archivos.write-readmewrite-readme
¿Qué nos llevamos?
Lo más valioso de este primer paso no es solo haber generado un README.md, sino haber practicado una forma de pensar scripts más claros:
comandos pequeños, responsabilidades separadas y validaciones visibles. Esa base
hace más fácil extender después el script, refactorizarlo o evolucionarlo hacia
flujos más ricos sin perder legibilidad.
¿Con ganas de más?
Referencias recomendadas
- “ Creating Modules ” en NushellExplica cómo construir módulos reutilizables en archivos
.nu, cómo importarlos con, qué se exporta y qué permanece local, y cómo escalar hacia submódulos,useuseyexport useexport use. Es la referencia clave para decidir cuándo un archivo debe pensarse como script y cuándo como módulo.export-envexport-env