flowchart TB
subgraph W["Terminal — la ventana (GUI)"]
subgraph S["Shell — el intérprete (bash / zsh / PowerShell)"]
C["tus comandos"]
end
end
W --> K["Sistema operativo: procesos, archivos, red, permisos"]
C -->|"exec()"| K
9 0.5. La terminal, en serio
Donde vive el backend, las cosas que nunca debes hacer, y tus nuevos compañeros de AI
La terminal es el escritorio del backend: este capítulo te da el tour esencial (navegar, pipes, procesos), las 12 cosas que jamás debes hacer y un mapa de los agentes de AI que ahora viven ahí.
9.1 El problema real
Tu aplicación funciona — en tu máquina, con VS Code abierto y npm run dev corriendo en una terminal integrada que cerras cuando terminas. Entonces llega el día: “hay que desplegarlo”. Y de repente todo es terminal: el servidor no tiene pantalla, Docker no tiene botones, los logs son un stream infinito, y la única forma de entrar a producción es ssh.
Un log es el diario del programa: qué pasó, cuándo, con qué request. Estructurado = en JSON con campos (request_id, user_id), para filtrar por máquina y no con los ojos.
La terminal (consola, línea de comandos) es la interfaz de texto con el sistema operativo: escribes comandos, lees resultados. Es como hablarle a la computadora por cartas en vez de señalar con el mouse.
En frontend la terminal era un accesorio. En backend es el escritorio donde trabajas. Este capítulo corto te pone cómodo ahí — y te dice qué cosas jamás hacer, porque la terminal no tiene Ctrl+Z.
9.2 Cómo se resuelve en un equipo
- Nadie memoriza comandos raros. Los equipos escriben runbooks: archivos con los comandos exactos para desplegar, ver logs, reiniciar.
- Los READMEs arrancan con comandos, no con prosa: “clona, corre esto, abre este puerto”.
Un puerto es una puerta numerada dentro de una computadora: la IP llega al edificio, el puerto al departamento. :3000 = “la app que escucha en el departamento 3000”. Postgres suele usar 5432, HTTP el 80, HTTPS el 443.
- Desde hace poco, la terminal tiene nuevos habitantes: los agentes de AI (Devin CLI, Claude Code, Copilot, Gemini CLI) viven ahí — porque la terminal es la interfaz universal donde se leen archivos y se ejecutan cosas.
Un CLI (Command Line Interface) es un programa que se usa escribiendo comandos en la terminal: git, npm, docker son CLIs. Lo contrario es una GUI (interfaz gráfica con botones).
9.3 Conceptos nuevos
- La diferencia entre terminal, shell y consola (son tres cosas).
- Qué es el PATH y por qué
command not foundexiste. - Exit codes: el contrato silencioso de todo comando.
- Pipes y redirección: componer programas como compones funciones.
- Las reglas de oro de lo que nunca se hace.
- Qué son los agentes CLI de AI y cómo trabajar con ellos sin que te rompan nada.
9.4 Explicación visual: tres capas que la gente confunde
- Terminal: solo la ventana que dibuja texto (Windows Terminal, iTerm, la pestaña de VS Code). No entiende nada.
- Shell: el programa que interpreta lo que escribes —
bash,zsh,fish,pwsh. El mismo comando puede significar cosas distintas en cada shell. - SO: quien realmente ejecuta: crea procesos, abre puertos, borra archivos.
Por eso export PORT=8000 funciona en bash pero en PowerShell es $env:PORT = "8000". Misma intención, distinto intérprete.
Esta decisión es material: necesitas un shell — pero cuál es como elegir el tipo de cimentación: todas sostienen, cambia el terreno donde mejor funcionan.
| Alternativa | Qué es | Qué te cuesta | Cuándo elegirla |
|---|---|---|---|
| bash | El estándar universal | Sintaxis vieja, quirks históricos | Scripts portables, servidores Linux — default seguro |
| zsh | bash mejorado (default en macOS) | Casi nada — compatible con bash | Uso diario en Mac/Linux |
| PowerShell / pwsh | Shell de objetos (no texto) | Sintaxis distinta; menos portable a Linux | Windows nativo, automatización .NET |
| fish | Autocompletado y UX moderna | NO compatible con sintaxis bash | Terminal interactiva, no scripts |
| Nushell | Datos estructurados en pipes | Joven; ecosistema pequeño | Curiosos, pipelines de datos |
| Git Bash (Windows) | bash emulado en Windows | No es Linux real — casos borde | Windows sin WSL; lo que usa este libro |
Y la terminal (la ventana): Windows Terminal, iTerm2, la integrada de VS Code — es decoración, elige la que te guste. El shell es lo que importa para los comandos.
9.5 El tour esencial
Nada de memorizar — esto es lo que usarás cada día, agrupado por intención:
9.5.1 Orientarse y archivos
pwd # dónde estoy
ls -la # qué hay aquí (con ocultos)
cd .. && cd - # subir / volver al directorio anterior
mkdir -p src/services # crear carpetas anidadas
cp .env .env.example # copiar
mv old.ts new.ts # mover/renombrar
cat app.log # ver un archivo
tail -f app.log # ver logs EN VIVO (el más usado en backend)9.5.2 Componer con pipes (la idea más poderosa)
cat app.log | grep ERROR | wc -l # cuántos errores hay
history | grep docker # qué comandos docker usé
curl -s localhost:8000/health # probar tu API sin navegador
echo "hello" > file.txt # escribir (sobreescribe)
echo "more" >> file.txt # añadir (append)| conecta la salida de un programa con la entrada del siguiente — es .map().filter() pero entre procesos completos.
Un bucle repite una acción por cada elemento o hasta cumplir una condición: for task in tasks hace algo con cada tarea. map y filter son bucles disfrazados de funciones — transforman/filtran colecciones sin for explícito.
Un diccionario (dict en Python, map en Go, objeto en JS) guarda parejas clave→valor: {"ana": 30}. Es la estructura que más aparece en JSON — un objeto JS es un diccionario.
Un proceso es un programa en ejecución: el sistema operativo le da memoria propia y un lugar en la fila del CPU. Tu API es un proceso; Postgres es otro; el navegador es varios. Que “se caiga el proceso” = el programa murió.
9.5.3 Procesos, puertos y exit codes
Ctrl+C # SIGTERM amable: "termina por favor"
kill -9 1234 # SIGKILL: mata sin dejar limpiar (último recurso)
netstat -ano | grep 8000 # Windows: quién ocupa el puerto
lsof -i :8000 # Unix: lo mismo
echo $? / echo $LASTEXITCODE # exit code del comando anterior (0 = ok)9.5.4 Variables de entorno
export PORT=8000 # bash/zsh
$env:PORT = "8000" # PowerShell
env | grep PORT # ver qué existeLas variables de entorno son cómo la config llega a tu app sin hardcodearla — el Cap. 24 vive de esto. Y tu repo ya lo usa: el .env con tu API key.
Una variable es una caja con nombre donde guardas un valor: let total = 42 guarda el 42 bajo el nombre total. Puedes leerla y cambiarla después (total = 50). const = caja que no se puede reemplazar.
Una variable de entorno es configuración que vive fuera del código: DATABASE_URL, JWT_SECRET. El mismo binario corre en dev y prod con distintas vars — los secretos nunca se escriben en el código.
Un entorno es una instancia completa donde corre tu app con su propia config y datos: local (tu máquina), staging (réplica de prueba), producción (la real). Cada entorno tiene sus propias llaves y su propia base de datos.
Un repositorio (repo) es la carpeta del proyecto con todo su historial Git adentro. GitHub/GitLab son servicios que hospedan repos para compartirlos y respaldarlos.
9.6 Las cosas que NUNCA debes hacer
rm -rfsin mirar el path dos veces. Jamás con variables que puedan estar vacías:rm -rf "$DIR/"conDIRvacío borra desde la raíz. Regla:echoel comando primero si hay variables.curl ... | bashsin leer el script. Estás ejecutando código arbitrario de internet, a veces como root. Descarga, lee, después ejecuta. Los instaladores serios te dejan revisar.Commitear secretos.
.env, keys, tokens, PEMs. Borrar el archivo después NO lo quita del historial de git — si se fue, hay que rotar la credencial (esto ya te pasó con una API key en este proyecto).sudopor costumbre. Si necesitas sudo para todo, algo está mal configurado (npm global, permisos de carpeta). sudo es el bisturí, no el martillo.chmod 777para “arreglar” permisos. “Funcionó” = le diste todo a todos. Entiende qué permiso falta (644archivos,755ejecutables).git push --forcea ramas compartidas (main,develop). Reescribes la historia de otros.--force-with-leaseen TU rama es el límite aceptable.Pegar comandos que no entiendes — especialmente de foros o con
sudo. Si no sabes qué hace, pregúntale a un AI CLI primero (“explícame este comando”) — para eso están.kill -9como primera opción. SIGKILL no deja al proceso cerrar conexiones ni escribir el último log. Primero Ctrl+C okill(SIGTERM);-9solo si ignora lo demás.Poner secretos en la línea de comandos:
mysql -pSuperSecretqueda enhistoryy es visible enps. Usa.env, flags interactivos o gestores de secretos.Rutas con espacios sin comillas:
cd C:\Repositorios\Grupo umbralfalla (dos argumentos);cd "C:\Repositorios\Grupo umbral"funciona. Ironía: este repo lo tiene.“Solo voy a probar rápido” en producción. No hay sandbox en prod:
DROP DATABASEno pregunta “¿estás seguro?”. Cualquier comando destructivo se ensaya en staging primero.docker run --privilegedo montar/por curiosidad. Le diste al contenedor tu máquina entera.
9.7 La nueva realidad: los CLI de AI
La terminal dejó de ser solo para comandos: desde hace unos años también es donde viven los agentes de AI — programas que leen tu repo, proponen cambios, editan archivos y ejecutan comandos por ti.
| CLI | Comando | Qué es |
|---|---|---|
| Devin CLI | devin |
Agente autónomo (el que está escribiendo este libro contigo) |
| Claude Code | claude |
Agente de Anthropic en tu repo |
| Gemini CLI | gemini |
Agente de Google, free tier generoso |
| Copilot CLI | gh copilot / copilot |
Sugerencias y agente de GitHub |
| Aider | aider |
Pair-programming open source por terminal |
¿Por qué viven en la terminal y no en una app con botones? Porque la terminal es la interfaz universal: todo lo que un dev puede hacer — leer archivos, correr tests, git, ssh — es un comando. Un agente que sabe usar la terminal sabe usar todo lo que tú usas.
9.7.1 Las reglas de oro aplican al agente también
Un agente es un junior muy rápido que a veces se equivoca con total confianza:
- Tú apruebas lo que ejecuta. Si propone
rm -rfo un--force, las reglas de arriba aplican igual — la responsabilidad es tuya. - Revisa el diff antes de commitear lo que escribió, como harías con el PR de un compañero.
- Nunca pegues secretos en el prompt.
.envy gestores de secretos, igual que con cualquier herramienta. - Dale contexto, no órdenes vagas: “agrega validación al endpoint POST /tasks de
src/routes/tasks.ts” funciona; “arregla el backend” no.
Explícame este comando antes de que lo ejecute: [pegar comando].
Quiero: qué hace cada flag y cada pipe, qué archivos/procesos toca, si
es destructivo o reversible, y la forma segura de lograr lo mismo si es
peligroso. No lo ejecutes — solo explícalo.
9.8 Errores comunes
command not found: el programa no está en el PATH. Revisa si está instalado y si tu terminal es vieja (el PATH se carga al abrirla — ya nos pasó conquarto).
PATH es la lista de carpetas donde la terminal busca programas cuando escribes un comando. Si node no está en el PATH, la terminal responde “command not found” aunque esté instalado en algún lado.
- “Cerré la terminal y sigue corriendo” (o al revés): procesos hijos,
nohup, servicios — Ctrl+C mata el foreground, no la familia. - Mezclar sintaxis de shells:
exportno existe en PowerShell,$env:no existe en bash. Mira qué shell tienes antes de pegar comandos de un tutorial.
9.9 Buenas prácticas
- El README empieza con los 3 comandos para correr el proyecto. Si necesitas más, ponlos en
scripts/o unMakefile. history+Ctrl+R: tu memoria está a una búsqueda de distancia.- Antes de un comando destructivo, la versión inofensiva:
lsdonde iría elrm,--dry-runsi existe,echodonde hay variables. - Scripts para lo que repites: si lo escribiste tres veces, es un archivo
.sh/.ps1commiteado.
EXTRA Los roadmaps piden dos cosas: comandos básicos de Git (clone, add, commit, push, pull, branch, merge) y servicios de alojamiento de repositorios:
- GitHub — la comunidad más grande; donde vive el open source y tu portafolio
- GitLab — ciclo completo en una plataforma (repos + CI/CD + issues)
- Bitbucket — el clásico del ecosistema Atlassian
- AWS CodeCommit — repos Git privados administrados por Amazon
El cometario que vale: tu perfil de GitHub es tu portafolio — los equipos que contratan lo miran antes que el CV.
9.10 Ejercicio
Sin salir de la terminal: (1) navega a un directorio temporal, (2) crea playground/logs/, (3) escribe tres líneas en app.log con >>, (4) cuenta las líneas con un pipe, (5) levanta python -m http.server 8000 (o npx serve), (6) pruébalo con curl desde otra terminal, (7) mátalo con Ctrl+C.
9.11 Mini reto
Un compañero te pega esto y te dice “córralo”:
cd /tmp && curl -sL https://example.com/setup.sh | bash && rm -rf $OLD_BUILDAntes de tocar nada: enumera las tres reglas de oro que viola.
9.12 Vocabulario técnico del capítulo
Una función es una receta reutilizable: recibe ingredientes (parámetros), hace pasos y devuelve un plato (return). La escribes una vez y la llamas mil veces: add(2, 3) → 5.
El parámetro es el hueco declarado en la función (def f(x) — x es parámetro); el argumento es el valor concreto que le pasas (f(42) — 42 es argumento). Mismo dato, dos momentos: declaración vs uso.
Un objeto es una colección de datos con nombre: {name: "Ana", age: 30} — cada dato es una propiedad (clave → valor). Python los llama dict, Go los arma con struct, TS con objetos/interface.
La autorización responde “¿qué puedes hacer?”: eres usuario válido (autenticado), pero ¿puedes borrar esta tarea? Se decide por rol o por ownership — y se verifica en cada request, no se recuerda.
Un token es una credencial portable: una cadena que dice quién eres y hasta cuándo. El servidor la emite tras el login; el cliente la presenta en cada request en vez de la contraseña.
Git es el historial de tu proyecto: cada commit es una foto del código con mensaje. Permite volver atrás, trabajar en ramas paralelas y fusionar el trabajo de varias personas sin pisarse.
localhost significa “esta misma máquina” — es la dirección que tu computadora usa para hablarse a sí misma. Cuando desarrollas, el “servidor” y el “cliente” viven en tu laptop: por eso todo es localhost:3000.
La memoria RAM es el escritorio de trabajo del programa: rápida, pero se borra al apagar. Los datos que deben sobrevivir van a disco o a la base de datos. Por eso let tasks = [] pierde todo al reiniciar.
9.13 Lo que deberías saber hacer ahora
Ejercicio (bash):
cd /tmp && mkdir -p playground/logs && cd playground
echo "INFO start" >> logs/app.log
echo "ERROR oops" >> logs/app.log
echo "INFO done" >> logs/app.log
cat logs/app.log | wc -l # 3
python -m http.server 8000 & # en otra terminal: curl localhost:8000
# Ctrl+C para detenerMini reto — las tres reglas violadas:
curl | bashejecuta código no revisado de internet (regla 2).rm -rf $OLD_BUILDusa una variable que puede estar vacía →rm -rf /(regla 1).- Y la meta-regla 7: correr algo que no entendiste. El flujo correcto:
curl -sL .../setup.sh -o setup.sh, leerlo, entonces decidir.
Pregunta de reflexión: ¿por qué crees que los agentes de AI viven en la terminal y no en una app gráfica? Si tu respuesta es “porque la terminal puede hacer todo lo que un dev hace”, entendiste el capítulo.