Funciones Puras

This commit is contained in:
2025-12-08 23:33:26 +01:00
parent be86b7441f
commit a9056f5909
3 changed files with 95 additions and 7 deletions

View File

@@ -9,7 +9,11 @@
"ca": "ca-ES" "ca": "ca-ES"
}, },
"dictionary": [ "dictionary": [
"Git" "Git",
"bash",
"subshells",
"subshells",
"Bash"
], ],
"syncDictionary": false, "syncDictionary": false,
"remoteDictionary": [], "remoteDictionary": [],

View File

@@ -14,7 +14,7 @@
"type": "markdown", "type": "markdown",
"state": { "state": {
"file": "Documentación personal/Mecanica de Unix/Bash Scripting Avanzado/Funciones puras.md", "file": "Documentación personal/Mecanica de Unix/Bash Scripting Avanzado/Funciones puras.md",
"mode": "preview", "mode": "source",
"source": false "source": false
}, },
"icon": "lucide-file", "icon": "lucide-file",
@@ -74,13 +74,11 @@
"title": "Marcadores" "title": "Marcadores"
} }
} }
], ]
"currentTab": 1
} }
], ],
"direction": "horizontal", "direction": "horizontal",
"width": 221.5, "width": 317.5
"collapsed": true
}, },
"right": { "right": {
"id": "519d5773673c1040", "id": "519d5773673c1040",
@@ -196,7 +194,7 @@
"obsidian-git:Open Git source control": false "obsidian-git:Open Git source control": false
} }
}, },
"active": "6baa04c1fda7d92f", "active": "e615f9321ff830be",
"lastOpenFiles": [ "lastOpenFiles": [
"Documentación personal/Mecanica de Unix/Bash Scripting Avanzado/Funciones puras.md", "Documentación personal/Mecanica de Unix/Bash Scripting Avanzado/Funciones puras.md",
"Documentación personal/Mecanica de Unix/Mecánica Unix - Manejo de la shell.md", "Documentación personal/Mecanica de Unix/Mecánica Unix - Manejo de la shell.md",

View File

@@ -38,3 +38,89 @@ total=$(sumar 10 5)
echo "El total es: $total" echo "El total es: $total"
``` ```
Esta función es aislada. Recibe datos, calcula y "devuelve" el dato imprimiéndolo (stdout), sin tocar nada más. Esta función es aislada. Recibe datos, calcula y "devuelve" el dato imprimiéndolo (stdout), sin tocar nada más.
### Ejemplo avanzado:
Procesamiento de texto puro
```Shell
trim_string() {
local input="$1"
# Elimina espacios al inicio y al final
sed 's/^[[:space:]]*//;s/[[:space:]]*$//' <<< "$input"
# Sed modifica streams, pero no toca el sistema, por ende, es válido.
# Es válido porque opera sobre datos y no modifica el sistema.
# En Bash, un comando externo sigue siendo "puro" mientras:
# - "No escriba en ficheros"
# - "No cambie el entorno"
# - "No tenga efectos secundarios"
# Usar comandos externos != impuro
}
texto_sucio=" Hola Mundo "
texto_limpio=$(trim_string "$texto_sucio")
echo "'$texto_sucio' -> '$texto_limpio'"
```
Aquí una función que limpia un string (quita espacios extra). Nota cómo no toca ningún archivo ni variable externa.
---
# El problema de BASH:
Es posible aplicar funciones puras a bash, pero el problema es que bash está pensado para tener efectos secundarios, como la modificación de ficheros y directorios (I/O). Así que es imposible tener un script de bash que tenga solo funciones puras, a no ser que su propósito no sea modificar ningún fichero ni directorio. Es decir, si tienes una función que se llama `crear_carpeta_local()`, ten por seguro de que será una función impura.
En Bash, es muy fácil romper la pureza, porque está orientado a efectos secundarios.
El motivo:
- Usa subshells
- Depende del entorno
- Depende del estado del sistema
- Incluso `echo`, en algunos casos mal utilizados, puede dar impureza al código por dar un valor que la función base no debe devolver. `echo` es aceptable en funciones puras siempre que imprima **únicamente** el valor que la función devuelve. Cualquier salida extra rompe la pureza.
>*Una "Función Pura" es solo un modelo conceptual: Una función que **se comporta como pura**, aunque en la práctica nunca es 100% pura.*
Es innecesario e incluso contraproducente intentar que *todo* sea puro en Bash. Hay que aplicar pureza **solo a funciones que procesan datos**.
---
# Reglas de purificación
Esto empieza a sonar como culto religioso.
Si quieres hacer funciones puras en bash, asegúrate de seguir estas reglas:
1. Usa siempre `local`.
Por defecto, todas las variables son globales. Si defines `i=1` dentro de una función, estás cambiando `i` en todo el script.
- **Regla**: Declara cada variable interna con local (o `declare -n` para referencias).
2. **Entradas solo por argumentos (`$1`, `$2`...)**
Nunca, NUNCA leas una variable global dentro de una función.
Si la función necesita un dato, pásalo como parámetro.
- *Mal*: `echo $USUARIO_GLOBAL`
- *Bien*: `local usuario=$1`
3. **Salidas por `stdout` (echo/printf)**
No asignes el resultado a una variable global. Imprímelo. Quien llame a la función va a capturar ese valor usando *command substitution* `var=$(mi_funcion).
- *Nota*: Usa `return` solo para indicar éxito (0) o error (no-0), no para devolver data.
4. **No escribas en stdout si la función se usa como "función pura interna"**.
Me explico; Si la función forma parte de un pipeline complejo, imprimir cosas rompe la composición.
Ejemplo de lo que NO se debe hacer:
```Shell
sumar() {
echo "$(( $1 + $2 ))"
echo "Suma completada" # Esto lo caga todo.
}
```
El problema no es imprimir como tal.
El problema es imprimir *cualquier cosa que no sea el valor* que la función debe devolver.
Es decir:
- **Pura**: Imprime SOLO el resultado.
- **Impura**: Imprime logs, mensajes, basura, colores, etc.
---
# El porqué de todo esto
Tal vez pienses que es más trabajo, pero los beneficios son enormes:
1. **La depuración es más sencilla**: Si algo, por alguna razón, falla, sabes que el error está *dentro* de ella o en los argumentos que recibió. No tienes que rastrear variables globales por todo el fichero.
2. **Reutilización**: Puedes hacer *copy-paste* de una función pura en otro script y funcionará inmediatamente sin romper nada (en la gran mayoría de casos).
3. **Seguridad**: Evita las colisiones de nombres de variables (el típico error donde dos bucles usan la variable `i` y uno rompe al otro).