Saltar al contenido principal

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 use , definir firmas tipadas, devolver strings y escribir validaciones explícitas cuando Nushell no ofrece un equivalente declarativo directo a los atributos de PowerShell.

Scripts ejecutables versus módulos importados con 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 export e importarlos con use .

Comando exportado por el módulo para reutilizar con use
scripts-nushell/scaffolding/readme-heading-module.nu
export def render-readme-heading [
    name: string,
    --verbose (-v)
] {
    if $verbose {
        print $"Preparing README heading for '($name)'"
    }

    $"# ($name)"
}

Detalles clave

  • def : define un comando en Nushell. Aquí render-readme-heading recibe argumentos, ejecuta un bloque y produce una salida que puede seguir fluyendo por el pipeline.
  • export : hace que el comando quede disponible para otros contextos cuando se importe el módulo con use . Sin export , la definición queda local al módulo.
  • Parámetros y flags: name: string es un parámetro obligatorio y tipado; la llamada debe proporcionar un valor. En cambio, --verbose (-v) es un flag opcional con nombre largo y alias corto, parecido a declarar [Alias('v')] [switch] $Verbose en PowerShell.
  • 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, $"Preparing README heading for '($name)'" reemplaza ($name) por el valor recibido como argumento.
  • Salida de depuración explícita: en este ejemplo usamos el patrón if $verbose { print ... } para emitir mensajes adicionales solo cuando el flag está presente. A diferencia de Write-Verbose en PowerShell, aquí no hay un canal de verbosidad equivalente activado automáticamente por -Verbose ; el comportamiento se modela de forma explícita en el propio comando.
  • 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 $"# ($name)" — se emite como salida del comando.

Uso

Importar el módulo y reutilizar su comando exportado
use ./scaffolding/readme-heading-module.nu *

render-readme-heading "Utility Scripts - DIBS" --verbose
render-readme-heading "Utility Scripts - DIBS" | describe
Desde scripts-nushell/

Detalles clave

  • use : importa definiciones exportadas desde un módulo .nu. En este caso importamos todas las definiciones con * , pero también podríamos haber importado solo [render-readme-heading] para limitar el alcance a ese comando específico.
  • describe : inspecciona el tipo de la salida que recibe por pipeline. Aquí sirve para verificar que render-readme-heading produce un valor de texto, no solo un efecto visual en pantalla.

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.

Generar el contenido inicial del README
scripts-nushell/scaffolding/readme-template-module.nu
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

  • use ./readme-heading-module.nu [render-readme-heading]: importa el comando exportado del módulo auxiliar para que render-readme-heading quede disponible y pueda reutilizarse dentro de este módulo.
  • let : permite asignar nombres a valores intermedios. Aquí se usa para guardar la marca temporal y también el encabezado generado por el comando auxiliar.
  • date now | format date "%Y-%m-%d %H:%M:%S": obtiene la fecha actual y la convierte en el formato que queremos insertar en el README.
  • Propagación manual del modo verboso: el bloque if $verbose { ... } else { ... } 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.
  • String multilínea interpolado: la expresión final usa $"..." para insertar ($heading) y ($timestamp) dentro del texto completo del archivo.
  • Retorno final: la última expresión del bloque se emite como salida del comando, así que new-readme produce un string que luego puede inspeccionarse, transformarse o enviarse por pipeline a otro comando (como save ).

Uso

Nota sobre importaciones entre módulos

readme-template-module.nu importa readme-heading-module.nu para reutilizar render-readme-heading . Luego, tu sesión interactiva solo necesita importar readme-template-module.nu con use para acceder a new-readme .

Igual que en PowerShell, conviene separar la lógica que produce datos de la que realiza efectos como escribir archivos. Aquí, new-readme 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.

Generar el contenido del README
use ./scaffolding/readme-template-module.nu *

new-readme "Utility Scripts - DIBS" --verbose
Desde scripts-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 [ValidateNotNullOrEmpty()] o [ValidateScript(...)]. Cuando la validación depende del contexto, lo habitual es escribirla de forma explícita dentro del comando o en una función auxiliar.

Validar el directorio y guardar el README
scripts-nushell/scaffolding/readme-writer-module.nu
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 $dir | path exists que la ruta exista, y luego con $dir | path type que corresponda específicamente a un directorio.
  • error make: 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.
  • Precondición explícita: ensure-output-dir 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.
  • Validación reutilizable: mover la comprobación a ensure-output-dir evita duplicación y permite reutilizar la misma regla en otros comandos que también escriban archivos.
  • Definición local del módulo: ensure-output-dir no se exporta, así que funciona como helper interno. En cambio, write-readme sí se exporta y constituye la API pública del módulo.
  • 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

Escribir el README en el directorio actual o personalizado
use ./scaffolding/readme-writer-module.nu *

write-readme "Utility Scripts - DIBS"
write-readme "Utility Scripts - DIBS" --out-dir ./demo
Desde scripts-nushell/.

Detalles clave

  • Ejecución simple: write-readme sin parámetro --out-dir guarda el README en el directorio actual (valor por defecto "." ).
  • Directorio personalizado: con el flag --out-dir o su alias -o puedes especificar otro directorio donde guardar el archivo. El comando validará que ese directorio exista antes de escribir.
  • Validación automática: si el directorio especificado no existe o no es un directorio, write-readme detiene la ejecución y emite un mensaje de error antes de escribir nada.

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 use , componer comandos que devuelven texto, y separar con claridad la generación del contenido de la escritura efectiva del archivo.

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

  • use importa definiciones exportadas desde módulos .nu y 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 new-readme de write-readme permite distinguir entre producir texto y realizar un efecto sobre el sistema de archivos.

¿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?