Espanso es una de esas herramientas pequeñas que, cuando encajan en tu forma de trabajar, te roban minutos al reloj cada día y luego no los devuelven nunca. Y eso es bueno.
Dicho sin épica innecesaria: Espanso es un expansor de texto a nivel de sistema.
Escribes algo corto… y se transforma automáticamente en algo largo.
Es el autocomplete de tu cerebro.
Instalación en Ubuntu
Antes de empezar. Espanso funciona de forma fiable en X11, no en Wayland. En Ubuntu moderno eso importa.
tgpt es un cliente no oficial que permite interactuar con modelos tipo ChatGPT directamente desde la terminal, sin navegador y sin iniciar sesión en OpenAI.
Se usa mucho para:
Resolver dudas técnicas rápidas
Explicar comandos Linux
Generar scripts
Pedir ejemplos de código
Documentar procesos
Automatizar consultas desde scripts
No sustituye el razonamiento humano. Es un copiloto, no el piloto.
ollama run llama3 "Escribe un README.md sobre este proyecto" > README.md
Aquí sí crea archivos, pero porque la shell redirige la salida. Ollama sigue sin tocar el sistema.
El peligro real
El riesgo no es Ollama. El riesgo es esto:
#Peligro eval "$(ollama run llama3 'dame un comando para limpiar el sistema')"
Ejecutar comandos con control (wrapper en Bash)
#!/bin/bash
if [ $# -gt 0 ]; then
pregunta$1
else
read -p "Pregunta a la IA: " pregunta
fi
respuesta=$(ollama run phi "$pregunta. Devuelve SOLO un comando seguro.")
echo "La IA propone ejecutar:"
echo "$respuesta"
read -p "¿Ejecutar? (s/n): " ok
if [[ "$ok" == "s" ]]; then
eval "$respuesta"
fi
Qué ocurre aquí:
Ollama propone
El humano autoriza
El sistema ejecuta
En Linux, un comando es solo:
un archivo ejecutable
ubicado en un directorio que esté en $PATH
Si eso se cumple → se ejecuta desde cualquier sitio.
Compruébalo:
echo $PATH
Verás cosas como:
/usr/bin
/usr/local/bin
/bin
Ahí es donde viven los comandos “del sistema”.
Opción recomendada: /usr/local/bin (limpio y correcto)
Supongamos que tu script se llama ollama-shell.sh.
#!/usr/bin/env bash
set -euo pipefail
# -----------------------------
# Ollama Shell Assistant (Seguro)
# - Pregunta a un modelo Ollama local
# - Fuerza español usando modelo "llama3-es"
# - Devuelve un único comando
# - Valida contra lista blanca
# - Pide confirmación antes de ejecutar
# - Registra todo en /var/log/ollama-shell.log
# -----------------------------
MODEL="${MODEL:-llama3-es}"
LOG_FILE="${LOG_FILE:-/var/log/ollama-shell.log}"
MODE="${MODE:-ask}" # ask | exec
TIMEOUT_SECS="${TIMEOUT_SECS:-120}"
# Lista blanca básica de comandos permitidos (ajústala a tu contexto)
ALLOW_CMDS=(
"ls" "ll" "pwd" "cd"
"cat" "less" "head" "tail"
"grep" "egrep" "fgrep" "awk" "sed" "cut" "sort" "uniq" "wc"
"find" "locate" "which" "whereis"
"ip" "ss" "netstat" "ping" "traceroute" "dig" "nslookup" "curl" "wget"
"ps" "top" "htop" "free" "df" "du" "uptime" "uname" "lsblk"
"systemctl" "journalctl"
"who" "w" "id" "groups" "last" "lastb"
"tar" "gzip" "gunzip" "zip" "unzip"
"apt" "apt-get" "dpkg" "snap"
"nmap"
)
print_help() {
cat <<'EOF'
Uso:
ollama-shell [-e] [-m MODELO] "pregunta..."
ollama-shell --suggest "pregunta..."
ollama-shell --exec "pregunta..."
ollama-shell --help
Opciones:
-m, --model Modelo Ollama a usar (por defecto: llama3-es)
-e, --exec Permite ejecutar (con confirmación humana)
--suggest Solo sugiere (no ejecuta)
--log FILE Archivo de log (por defecto: /var/log/ollama-shell.log)
Variables:
MODEL=llama3-es
MODE=ask|exec
LOG_FILE=/var/log/ollama-shell.log
TIMEOUT_SECS=120
Notas:
- El modelo debe devolver SOLO UN comando.
- Se valida el comando contra una lista blanca básica.
EOF
}
die() {
echo "ERROR: $*" >&2
exit 1
}
ensure_ollama() {
command -v ollama >/dev/null 2>&1 || die "No encuentro 'ollama' en PATH. ¿Está instalado?"
systemctl is-active --quiet ollama 2>/dev/null || true
}
ensure_log_writable() {
# Intentar escribir en LOG_FILE; si no se puede, degradar a ~/.ollama-shell.log
if ! (touch "$LOG_FILE" 2>/dev/null); then
LOG_FILE="$HOME/.ollama-shell.log"
touch "$LOG_FILE" || die "No puedo escribir logs ni en /var/log ni en HOME."
fi
}
log_line() {
local msg="$1"
printf '%s | user=%s | cwd=%s | %s\n' "$(date '+%F %T')" "${USER:-unknown}" "$(pwd)" "$msg" >> "$LOG_FILE"
}
trim() {
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
}
first_token() {
# Devuelve el primer token (comando base), ignorando sudo si aparece
local s="$1"
s="$(echo "$s" | trim)"
if [[ "$s" == sudo\ * ]]; then
echo "$s" | awk '{print $2}'
else
echo "$s" | awk '{print $1}'
fi
}
is_allowed_cmd() {
local cmd="$1"
for a in "${ALLOW_CMDS[@]}"; do
[[ "$cmd" == "$a" ]] && return 0
done
return 1
}
looks_dangerous() {
# Filtros anti-destrucción básicos (no exhaustivos)
local s="$1"
s="$(echo "$s" | trim)"
[[ -z "$s" ]] && return 0
# Cosas típicas peligrosas
if echo "$s" | grep -Eqi 'rm\s+-rf\s+/' ; then return 0; fi
if echo "$s" | grep -Eqi 'mkfs|dd\s+if=|:\(\)\s*\{\s*:\|\s*:\s*;\s*\}\s*;|shutdown|reboot|poweroff' ; then return 0; fi
if echo "$s" | grep -Eqi '>\s*/etc/|>\s*/bin/|>\s*/usr/bin/|chown\s+root|chmod\s+4[0-7]{3}|chmod\s+u\+s' ; then return 0; fi
# Inyección obvia
if echo "$s" | grep -Eqi '\$\(|`' ; then return 0; fi
return 1
}
ask_ollama_for_command() {
local question="$1"
local prompt
prompt=$(
cat <<EOF
Eres un asistente técnico experto en Linux y ciberseguridad.
Respondes SIEMPRE en español.
Tu tarea: proponer EXACTAMENTE UN comando de terminal (una sola línea) para ayudar con la petición del usuario.
REGLAS:
- Devuelve SOLO el comando. Sin explicaciones. Sin comillas. Sin markdown.
- El comando debe ser lo más seguro posible (preferir lectura/consulta a escritura).
- Evita acciones destructivas. No uses rm, mkfs, dd, ni cambios de permisos peligrosos.
Petición del usuario:
$question
EOF
)
# Timeout para evitar bloqueos largos
# Nota: 'timeout' suele estar en coreutils
if command -v timeout >/dev/null 2>&1; then
timeout "$TIMEOUT_SECS" ollama run "$MODEL" "$prompt" 2>/dev/null | head -n 1 | trim
else
ollama run "$MODEL" "$prompt" 2>/dev/null | head -n 1 | trim
fi
}
confirm() {
local msg="$1"
read -r -p "$msg (s/n): " ans
[[ "${ans,,}" == "s" ]]
}
main() {
local question=""
local explicit_mode=""
local explicit_model=""
local explicit_log=""
while [[ $# -gt 0 ]]; do
case "$1" in
-m|--model) explicit_model="$2"; shift 2 ;;
-e|--exec) explicit_mode="exec"; shift ;;
--suggest) explicit_mode="ask"; shift ;;
--log) explicit_log="$2"; shift 2 ;;
-h|--help) print_help; exit 0 ;;
*)
# Resto como pregunta (permitimos comillas)
question="$*"
break
;;
esac
done
[[ -n "$explicit_model" ]] && MODEL="$explicit_model"
[[ -n "$explicit_mode" ]] && MODE="$explicit_mode"
[[ -n "$explicit_log" ]] && LOG_FILE="$explicit_log"
[[ -z "$question" ]] && die "Falta la pregunta. Usa --help para ver ejemplos."
ensure_ollama
ensure_log_writable
log_line "question=$(printf '%q' "$question") model=$MODEL mode=$MODE"
local cmd
cmd="$(ask_ollama_for_command "$question")"
log_line "raw_cmd=$(printf '%q' "$cmd")"
[[ -z "$cmd" ]] && die "El modelo no devolvió un comando."
# Validaciones básicas
if looks_dangerous "$cmd"; then
log_line "blocked_reason=dangerous_pattern"
die "Comando bloqueado por patrón peligroso: $cmd"
fi
local base
base="$(first_token "$cmd")"
if ! is_allowed_cmd "$base"; then
log_line "blocked_reason=not_in_allowlist base=$base"
die "Comando bloqueado (no está en la lista blanca): $base"
fi
echo "$cmd"
if [[ "$MODE" == "exec" ]]; then
if confirm "¿Ejecutar el comando anterior?"; then
log_line "exec=YES cmd=$(printf '%q' "$cmd")"
# Ejecuta tal cual (sin eval). Bash interpretará la línea como comando.
bash -lc "$cmd"
else
log_line "exec=NO"
echo "Cancelado."
fi
else
echo "Modo sugerencia (no ejecuto nada). Usa --exec para permitir ejecución con confirmación."
fi
}
main "$@"
Arqueología del videojuego y evolución del hardware
Contexto de la actividad
En esta sesión realizaremos una actividad práctica y lúdica utilizando Raspberry Pi con juegos retro y gafas de realidad virtual (VR). El objetivo no es solo jugar, sino analizar un videojuego clásico como producto tecnológico, entendiendo el hardware en el que nació, comparándolo con ordenadores profesionales de su época y reflexionando sobre cómo podría adaptarse al hardware actual.
Los videojuegos retro son un excelente ejemplo de cómo la creatividad y el diseño se adaptaban a fuertes limitaciones técnicas. Esta actividad te propone investigar, comparar y soñar… pero siempre con base técnica.
Desarrollo de la actividad
Fase 1 · Exploración del juego (en clase)
Durante la sesión en clase:
Utilizarás una Raspberry Pi con emuladores y mandos.
Seleccionarás un único videojuego retro de cualquiera de las plataformas disponibles (arcade, NES, SNES, Mega Drive, PlayStation, etc.).
Jugarás durante un tiempo limitado con el objetivo de observar, no de completar el juego.
Debes fijarte especialmente en:
Tipo de controles
Gráficos y estilo visual
Sonido y música
Dificultad
Ritmo del juego
Fase 2 · Ficha técnica del videojuego
En el trabajo a entregar deberás incluir una ficha con la siguiente información:
Nombre del videojuego
Año aproximado de lanzamiento
Plataforma o plataformas originales
Tipo de juego (plataformas, shooter, puzzle, etc.)
Fase 3 · Análisis de la plataforma original
Analiza el hardware original para el que fue creado el juego:
Número de bits de la plataforma (8, 16, 32 bits, etc.)
Tipo de CPU (si se conoce)
Memoria aproximada
Resolución gráfica típica
Tipo de soporte (cartucho, CD, placa arcade…)
Reflexiona brevemente sobre qué limitaciones técnicas tenía esa plataforma y cómo influyeron en el diseño del juego.
Mientras jugábamos… ¿qué usaban los profesionales?
Fase 4 · Hardware profesional contemporáneo
Investiga qué ordenadores u estaciones de trabajo de uso profesional existían en la misma época que la plataforma de tu juego.
Debes elegir al menos uno y responder:
Nombre del equipo
CPU utilizada
Cantidad de memoria
Sistema operativo
Uso principal (científico, empresarial, diseño, programación, etc.)
Ejemplos orientativos (puedes usar otros):
IBM PC / PC-AT
Apple Macintosh
Commodore Amiga
Atari ST
Estaciones Sun, DEC, SGI, NeXT…
Fase 5 · Comparación técnica
Compara el hardware del videojuego con el ordenador profesional investigado:
¿Cuál tenía más potencia?
¿Cuál tenía más memoria?
¿Cuál tenía mejores capacidades gráficas reales?
¿Cuál era más caro?
¿Por qué, pese a existir hardware más potente, los juegos se desarrollaban para consolas?
Fase 6 · De lo profesional a lo doméstico
Reflexiona sobre la evolución tecnológica:
¿Qué tecnologías que antes eran profesionales hoy son comunes?
Gráficos acelerados
Sonido digital
Multitarea
Redes
¿En qué momento los ordenadores domésticos superaron a las consolas clásicas?
Fase 7 · El salto a la actualidad: Raspberry Pi
Analiza el papel de la Raspberry Pi:
¿Qué tipo de ordenador es?
¿Se parece más a una consola antigua o a un PC profesional antiguo?
¿Qué usos profesionales reales tiene hoy?
Servidores
Automatización
IoT
Educación
Fase 8 · Imaginando el juego en Realidad Virtual
Durante la sesión podrás probar gafas VR.
En el trabajo deberás responder:
¿Cómo se podría adaptar tu juego a realidad virtual?
Tipo de vista (primera persona, tercera persona, maqueta…)
Controles
Escala del mundo
¿Qué elementos deberían mantenerse para que siga siendo el mismo juego?
¿Qué problemas técnicos podrían aparecer?
Mareos
Latencia
Precisión de controles
Rendimiento
Pregunta final de reflexión
Responde de forma razonada:
Si tuvieras que explicar qué es una Raspberry Pi a alguien de la época de tu videojuego, usando solo comparaciones con hardware antiguo… ¿qué dirías?