Shell interactivo minimalista en C para aprender fork, exec, tuberías, redirección, expansiones y edición de línea con historial.
make # genera el ejecutable termina-L-ndo
make run # compila (si hace falta) y ejecuta
make clean # borra .o y el binario./termina-L-ndo
help
echo hola
echo mundo
# Pulsa ↑ para ver "mundo", otra vez ↑ para "hola"
# Pulsa ↓ para volver hacia comandos más recientes
history
exit| Área | Qué hace | Ejemplo |
|---|---|---|
| Comandos externos | fork + execvp |
ls -la, gcc -Wall main.c |
| Comandos internos | Sin crear proceso hijo | cd, pwd, echo, help, … |
| Tuberías | Un proceso por etapa unido con | |
ls | grep .c | wc -l |
| Redirección | <, >, >> |
wc -l < lista.txt |
| Segundo plano | & al final |
sleep 10 & |
| Variables | $VAR, export, unset |
echo $HOME |
| Código de salida | $? y color del prompt |
false → prompt rojo; echo $? → 1 |
| Sustitución | $(cmd) y `cmd` |
echo "Hoy: $(date +%Y)" |
| Globbing | glob(3) en la shell |
ls *.c, cat src/*.h |
| Historial | Cola circular (50 líneas) | history |
| Flechas ↑ ↓ | Navegar comandos en el prompt | Ver sección siguiente |
| TAB | Autocompletar comando o ruta | ec+TAB → echo |
| Edición de línea | Prompt fijo, modo raw (termios) |
Retroceso no borra el sufijo $> |
| Ruta en prompt | Directorio actual (getcwd, ~ = $HOME) |
~/proyecto $> |
| Colores ANSI | Salida de la shell coloreada | help, errores, history |
| Comentarios | # hasta fin de línea |
ls # listar |
| Comillas | '…' literal, "…" con $ |
echo "ruta: $HOME" |
Dentro del shell puedes escribir help para ver un resumen coloreado en pantalla. Esta sección describe los mismos comandos y características que aparecen ahí, con más detalle y ejemplos.
Los comandos internos se ejecutan en el propio proceso del shell (no llaman a fork para el programa del comando). Solo aplican si son el único comando de la línea y no llevan redirección (<, >, >>).
| Comando | Descripción | Ejemplos |
|---|---|---|
cd [dir] |
Cambia el directorio de trabajo. Sin argumentos usa $HOME. - vuelve al directorio anterior (como en bash). |
cd /tmp, cd, cd - |
pwd |
Imprime la ruta absoluta del directorio actual (salida en cian). | pwd |
exit [n] |
Termina el shell. El código opcional n se devuelve al sistema (por defecto 0). |
exit, exit 1 |
export |
Sin argumentos: lista todas las variables de entorno. Con NOMBRE=valor: define o actualiza una variable. |
export, export PATH=/usr/bin |
unset VAR |
Elimina la variable de entorno VAR. |
unset MI_VAR |
echo ... |
Escribe los argumentos en una línea (separados por espacio) y un salto de línea. | echo hola mundo, echo $HOME |
history |
Muestra los últimos comandos guardados, numerados del 1 al N (números en amarillo). Máximo 50 entradas. | history |
help |
Muestra el banner y esta misma ayuda resumida en la terminal. | help |
clear |
Limpia la pantalla (intenta el programa clear; si falla, usa secuencias ANSI). |
clear |
Cualquier otro nombre (por ejemplo ls, gcc, cat) se busca en las carpetas de $PATH y se ejecuta con execvp en un proceso hijo.
Lo que help lista como «Características» son extensiones del intérprete: funcionan también mezcladas en la misma línea (salvo las teclas, que actúan al editar).
| Sintaxis | Qué hace | Ejemplo |
|---|---|---|
| |
Tubería: la salida estándar de un comando alimenta la entrada del siguiente. Un proceso por etapa. | ls | grep .c | wc -l |
< |
Redirección de entrada: lee desde un archivo en lugar del teclado. | wc -l < lista.txt |
> |
Redirección de salida: escribe en un archivo (lo crea o trunca). | ls > salida.txt |
>> |
Añadir a archivo: la salida se agrega al final sin borrar el contenido previo. | echo log >> app.log |
& |
Segundo plano: el último comando del pipeline no bloquea el shell; se muestra su PID. | sleep 60 & |
# |
Comentario: el resto de la línea se ignora al parsear. | ls -la # ver todo |
$VAR |
Variable de entorno: se sustituye por el valor de VAR (vacío si no existe). |
echo $HOME |
$? |
Código de salida del último comando ejecutado (0 = éxito). También colorea el prompt. |
false; echo $? |
$(cmd) o `cmd` |
Sustitución de comando: ejecuta cmd, captura su salida estándar y la inserta en la línea (sin salto de línea final). |
echo "Ruta: $(pwd)" |
*, ?, […] |
Comodines (glob): la shell expande patrones en argumentos antes de execvp (no el programa hijo). Sin coincidencias, el patrón queda literal. |
ls *.c, cat src/*.h |
| Flechas ↑ / ↓ | Historial en el prompt: recorre comandos ya ejecutados; ↓ restaura lo que estabas escribiendo. | Tras echo a y echo b, ↑ muestra b |
| TAB | Autocompletado del último token: comandos (builtins + PATH) o rutas de archivos. Segunda TAB lista opciones. |
ec+TAB → echo |
- El prompt muestra la ruta actual en cian y el sufijo
$>en verde si el último comando tuvo éxito, o en rojo si falló. - Para desactivar colores:
export NO_COLOR=1(también se desactivan si la salida no es una terminal).
El historial se guarda en memoria al ejecutar cada comando (no al pulsar Enter en líneas vacías). Hasta 50 entradas; las más antiguas se descartan cuando se llena el buffer.
| Tecla | Acción |
|---|---|
| ↑ | Muestra el comando anterior (el más reciente la primera vez) |
| ↓ | Muestra el comando siguiente; al pasar el último, restaura lo que estabas escribiendo |
| Retroceso | Borra solo lo que escribiste; el prompt $> no se puede borrar |
| Enter | Ejecuta la línea (puedes editar un comando recuperado antes) |
| Ctrl+C | Cancela la línea actual y muestra un prompt nuevo |
| Ctrl+D | Cierra el shell si la línea está vacía |
| TAB | Completa comando (builtins + PATH), archivo o carpeta; TAB otra vez lista opciones |
Comportamiento similar a bash: si empiezas a escribir o borras tras usar las flechas, vuelves al modo «línea nueva» y el historial no sobrescribe tu borrador hasta que pulses ↑ de nuevo.
El comando history imprime la lista numerada (índices en amarillo). Las flechas usan la misma lista interna.
| Elemento | Color habitual |
|---|---|
| Ruta en prompt | Cian |
Sufijo $> (éxito) |
Verde, negrita |
Sufijo $> (error) |
Rojo, negrita |
| Mensajes de error | Rojo (termina-L-ndo: …) |
history (números) |
Amarillo |
pwd |
Cian |
help (banner, comandos) |
Cian / magenta / verde |
| Jobs en background | Cian |
Desactivar colores:
export NO_COLOR=1También se desactivan si la salida no es una terminal (por ejemplo al redirigir a un archivo).
shell_read_line(&history) # termios + flechas; o getline si no hay tty
→ trim
→ history_add() # guarda comando (sin duplicar el último)
→ expand_substitutions() # $(...) y `...`
→ parse_line() # tokens, pipes, redirecciones, $VAR
→ expand_globs() # *.c, etc.
→ run_builtin() o execute_pipeline()
→ shell_set_status() # $? y color del prompt
include/shell.h — tipos, constantes, API pública
src/main.c — bucle REPL; pasa History a lectura y ejecución
src/input.c — lectura carácter a carácter, prompt protegido, flechas
src/complete.c — autocompletado con TAB (comandos y archivos)
src/parser.c — tokenización, comillas, pipes, redirecciones
src/executor.c — fork, exec, pipes, señales, wait
src/builtins.c — comandos integrados y ayuda coloreada
src/history.c — cola circular; usado por history y por input.c
src/utils.c — trim, $VAR, $?, prompt, último status
src/expand.c — sustitución $(...) y glob con <glob.h>
src/colors.c — ANSI, NO_COLOR, shell_error / shell_fprintf
Makefile — compilación con gcc -std=c11 -Wall
Cada archivo .c incluye comentarios en español que explican el propósito de las funciones y los pasos relevantes del algoritmo.
- Entrada interactiva (
input.c): se desactivanICANONyECHO; la shell pinta cada carácter y gestiona retroceso y secuenciasESC [ A/ESC [ B(flechas). - Autocompletado (
complete.c): TAB completa el último token (builtins, ejecutables enPATH, archivos y carpetas del directorio actual o ruta parcial). - Prompt: muestra el directorio de trabajo actual (p. ej.
~/termina-L-ndo $>);~sustituye a$HOME. El sufijo$>no se borra con retroceso en línea vacía. - Historial: índices 1…N en
history_get()(1 = más antiguo, N = más reciente);input.cguarda un borrador al pulsar ↑ por primera vez. - Ctrl+C interrumpe el comando en ejecución; no cierra el shell. Durante la lectura de línea, cancela la entrada actual.
- Sustitución
$(…): subproceso con stdout capturado; se elimina el salto de línea final. - Glob: si no hay coincidencias, el patrón se deja literal (como bash por defecto).
- Scripts / tuberías: sin tty se usa
getline()(sin flechas ni edición especial).
- GCC o compilador C11
- Linux / POSIX (
getline,fork,glob,termios,isatty)