293 lines
7.7 KiB
Markdown
293 lines
7.7 KiB
Markdown
# Minishell - Guia de estructura y pasos (parte obligatoria)
|
|
|
|
Objetivo de este documento
|
|
- Proponer una estructura de archivos y datos.
|
|
- Describir el proceso paso a paso como tutorial.
|
|
- Servir de guion para defensa (explicaciones claras y ordenadas).
|
|
|
|
Este documento no implementa nada. Solo define el plan y el por que.
|
|
|
|
---
|
|
|
|
## 1. Vision general del flujo
|
|
|
|
El shell se puede explicar como una tuberia de fases:
|
|
1. Lectura interactiva (prompt + historial).
|
|
2. Tokenizacion (lexing) con comillas y metacaracteres.
|
|
3. Parseo (construccion de comandos, redirecciones, pipes).
|
|
4. Expansion de variables ($VAR y $?).
|
|
5. Preparacion de ejecucion (resolucion de rutas, heredoc).
|
|
6. Ejecucion (builtins o execve) con pipes y redirecciones.
|
|
7. Gestion de exit status y señales.
|
|
|
|
Esta separacion permite explicar en defensa cada pieza por separado y justificar
|
|
las decisiones tecnicas.
|
|
|
|
---
|
|
|
|
## 2. Propuesta de estructuras de datos
|
|
|
|
Estas estructuras son solo guia. Adapta nombres a tu estilo y Norminette.
|
|
|
|
### 2.1 Token (lexer)
|
|
Representa una unidad del input (palabra, pipe, redireccion, etc.).
|
|
|
|
- enum e_tokentype
|
|
- TOK_WORD
|
|
- TOK_PIPE
|
|
- TOK_REDIR_IN (<)
|
|
- TOK_REDIR_OUT (>)
|
|
- TOK_REDIR_APPEND (>>)
|
|
- TOK_HEREDOC (<<)
|
|
|
|
- struct s_token
|
|
- char *text
|
|
- t_tokentype type
|
|
- struct s_token *next
|
|
|
|
Uso en defensa: el lexer separa el input en unidades, respetando comillas.
|
|
|
|
### 2.2 Redireccion
|
|
Guarda los datos de redireccion por comando.
|
|
|
|
- enum e_redirtype
|
|
- REDIR_IN
|
|
- REDIR_OUT
|
|
- REDIR_APPEND
|
|
- REDIR_HEREDOC
|
|
|
|
- struct s_redir
|
|
- t_redirtype type
|
|
- char *target
|
|
- int fd
|
|
- struct s_redir *next
|
|
|
|
Notas:
|
|
- target es el filename o delimitador de heredoc.
|
|
- fd se resuelve en fase de preparacion (open o pipe temporal).
|
|
|
|
### 2.3 Comando
|
|
|
|
- struct s_command
|
|
- char **argv
|
|
- int argc
|
|
- char *path
|
|
- t_redir *redirs
|
|
|
|
### 2.4 Pipeline
|
|
Una lista de comandos en orden, unidos por pipes.
|
|
|
|
- struct s_pipeline
|
|
- t_command **cmds
|
|
- size_t count
|
|
|
|
|
|
---
|
|
|
|
## 3. Lexer: reglas y pasos
|
|
|
|
Reglas clave del subject:
|
|
- No interpretar comillas sin cerrar.
|
|
- Comilla simple: no se expanden variables ni metacaracteres.
|
|
- Comilla doble: se expanden variables, pero se respetan caracteres normales.
|
|
- Metacaracteres: |, <, >, <<, >> separan tokens.
|
|
|
|
Pasos recomendados:
|
|
1. Recorrer la linea caracter a caracter.
|
|
2. Mantener estado: in_single, in_double.
|
|
3. Cuando no estas en comillas, detectar metacaracteres y cortar tokens.
|
|
4. Construir TOK_WORD con el texto exacto (sin eliminar comillas aun).
|
|
5. Si llegas a fin de linea con in_single o in_double activo, error de parseo.
|
|
|
|
Explicacion para defensa:
|
|
- El lexer no sabe de ejecucion, solo separa en tokens validos.
|
|
- El manejo de comillas se hace aqui para respetar la sintaxis del shell.
|
|
|
|
---
|
|
|
|
## 4. Parser: construccion de comandos
|
|
|
|
Objetivo: transformar tokens en una estructura ejecutable.
|
|
|
|
Pasos:
|
|
1. Recorrer lista de tokens.
|
|
2. Cada TOK_PIPE cierra un comando actual y abre el siguiente.
|
|
3. TOK_WORD se agrega a argv.
|
|
4. TOK_REDIR_* consume el siguiente token (debe ser TOK_WORD) como target.
|
|
5. Construir lista de redirecciones para cada comando.
|
|
6. Validar errores: pipe inicial/final, redireccion sin target, etc.
|
|
|
|
Explicacion para defensa:
|
|
- El parser aplica reglas de orden y construye una estructura clara.
|
|
- Separar argv y redirecciones evita mezclar logica en executor.
|
|
|
|
---
|
|
|
|
## 5. Expansion de variables
|
|
|
|
Reglas:
|
|
- $VAR se sustituye por getenv/tabla interna.
|
|
- $? se sustituye por el exit_status anterior.
|
|
- En comilla simple no se expande.
|
|
- En comilla doble si se expande.
|
|
|
|
Proceso recomendado:
|
|
1. Durante tokenizacion, guardar el texto con sus comillas o bien
|
|
marcar segmentos con estado de comillas.
|
|
2. En expansion, recorrer cada palabra y reemplazar $...
|
|
3. Si variable no existe, reemplazar por string vacio.
|
|
4. Eliminar comillas despues de la expansion.
|
|
|
|
Explicacion para defensa:
|
|
- La expansion es una fase separada para no complicar el parser.
|
|
- $?, variable especial, refleja el estado de la ultima ejecucion.
|
|
|
|
---
|
|
|
|
## 6. Redirecciones y heredoc
|
|
|
|
Redirecciones basicas:
|
|
- <: open(file, O_RDONLY)
|
|
- >: open(file, O_WRONLY | O_CREAT | O_TRUNC)
|
|
- >>: open(file, O_WRONLY | O_CREAT | O_APPEND)
|
|
|
|
Heredoc (<<):
|
|
1. Leer lineas hasta delimitador exacto.
|
|
2. Guardar el contenido en un pipe o fichero temporal.
|
|
3. Usar el extremo de lectura como STDIN del comando.
|
|
4. No guardar el contenido en historial.
|
|
|
|
Explicacion para defensa:
|
|
- Las redirecciones se resuelven antes de ejecutar el proceso.
|
|
- Heredoc es una fuente especial de entrada.
|
|
|
|
---
|
|
|
|
## 7. Resolucion de comandos y PATH
|
|
|
|
Reglas:
|
|
- Si argv[0] es una ruta absoluta o relativa (/, ./, ../), usarla tal cual.
|
|
- Si no, buscar en PATH separando por ':'.
|
|
- Si es builtin, no se necesita path real.
|
|
|
|
Proceso:
|
|
1. Detectar builtin.
|
|
2. Si no builtin y no es ruta, recorrer PATH y usar access().
|
|
3. Guardar path en t_command->path.
|
|
|
|
---
|
|
|
|
## 8. Ejecucion
|
|
|
|
Caso 1: comando unico builtin
|
|
- Ejecutar en el proceso padre para que pueda modificar estado del shell
|
|
(ej: cd, export, unset, exit).
|
|
|
|
Caso 2: pipeline o comando externo
|
|
- Usar fork + execve.
|
|
- Crear pipes entre comandos.
|
|
- Aplicar redirecciones antes de ejecutar.
|
|
|
|
Proceso para pipeline:
|
|
1. Para cada comando, crear pipe si hay siguiente.
|
|
2. fork.
|
|
3. En child: dup2 para redirecciones y pipes, luego ejecutar.
|
|
4. En parent: cerrar FDs innecesarios y seguir.
|
|
5. Esperar procesos, guardar exit status del ultimo comando.
|
|
|
|
Explicacion para defensa:
|
|
- Las pipes conectan stdout del comando i con stdin del comando i+1.
|
|
- Los builtins dentro de pipeline se ejecutan en child.
|
|
|
|
---
|
|
|
|
## 9. Builtins obligatorios
|
|
|
|
- echo con -n
|
|
- cd (ruta relativa o absoluta)
|
|
- pwd
|
|
- export (sin opciones)
|
|
- unset (sin opciones)
|
|
- env (sin opciones o argumentos)
|
|
- exit
|
|
|
|
Notas de defensa:
|
|
- export/unset trabajan sobre la tabla de variables del shell.
|
|
- env imprime variables de entorno.
|
|
- exit debe actualizar exit_status y terminar el loop principal.
|
|
|
|
---
|
|
|
|
## 10. Senales
|
|
|
|
Requisitos interactivos:
|
|
- ctrl-C: imprime nueva linea y muestra prompt.
|
|
- ctrl-D: termina el shell.
|
|
- ctrl-\: no hace nada.
|
|
|
|
Regla del subject:
|
|
- Solo una variable global para indicar la senal recibida.
|
|
|
|
Proceso:
|
|
1. Definir una variable global int g_signal.
|
|
2. Configurar handlers con sigaction.
|
|
3. En handler: actualizar g_signal y escribir un '\n' si procede.
|
|
4. En el loop principal: si g_signal indica SIGINT, resetear lineas de readline.
|
|
|
|
---
|
|
|
|
## 11. Manejo de errores y salida
|
|
|
|
- Mostrar errores con perror o mensajes consistentes.
|
|
- Si parseo falla, no ejecutar nada.
|
|
- Mantener exit_status actualizado.
|
|
|
|
Explicacion en defensa:
|
|
- Un shell robusto evita ejecutar comandos parcialmente parseados.
|
|
- exit_status es clave para $?.
|
|
|
|
---
|
|
|
|
## 12. Checklist para defensa (guion rapido)
|
|
|
|
1. Explico el flujo completo: lectura -> lexer -> parser -> expansion -> exec.
|
|
2. Explico como manejo comillas y metacaracteres.
|
|
3. Explico como construyo argv y redirecciones.
|
|
4. Explico expansion de $VAR y $?.
|
|
5. Explico pipes y redirecciones con dup2.
|
|
6. Explico por que los builtins se ejecutan en parent o child.
|
|
7. Explico manejo de senales y la variable global unica.
|
|
8. Explico exit_status y comportamiento de $?.
|
|
|
|
---
|
|
|
|
## 13. Sugerencia de estructura de archivos
|
|
|
|
- include/
|
|
- minishell.h
|
|
- core.h (estructuras globales y estado)
|
|
- parser.h (tokens, parser)
|
|
- executor.h
|
|
- builtins.h
|
|
|
|
- src/
|
|
- core/ (init, signals, util)
|
|
- parser/ (lexer.c, parser.c, expand.c)
|
|
- executor/ (executor.c, redirs.c)
|
|
- builtins/ (echo, cd, pwd, exit, env, export, unset)
|
|
- variables/ (environment.c)
|
|
- minishell.c (loop principal)
|
|
- main.c
|
|
|
|
Esto es solo una guia; no es obligatorio seguirla al pie de la letra.
|
|
|
|
---
|
|
|
|
## 14. Consejos para la defensa
|
|
|
|
- Usa bash como referencia de comportamiento.
|
|
- Demuestra un par de ejemplos: pipe, redireccion y expansion.
|
|
- Si algo falla, explica que el parser previene ejecucion parcial.
|
|
- Recalca el manejo correcto de ctrl-C y ctrl-\.
|
|
|