1
0
Fork 0
mirror of https://gitlab.com/pnx/gosh synced 2026-06-15 23:03:09 +02:00
gosh/README.md
2025-10-27 02:03:02 +01:00

106 lines
3.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Gosh - a tiny educational shell in Go
Gosh is a small, readable shell written in Go.
Its designed as an educational project: the code favors clarity over completeness so
you can learn how a shell works by reading and modifying it.
What youll find here:
- A minimal interactive loop that reads input, parses it into a command, and executes it.
- A simple builtin registry (e.g., `cd`, `exit`).
- A executor that decides whether to run a builtin or spawn an external program.
- A handful of small packages (parser, prompt, paths) that keep responsibilities focused and names unambiguous.
Quick start
-----------
Requirements: Go 1.25+
- Build: `go build ./cmd/gosh`
- Run: `go run ./cmd/gosh`
You should see a prompt like: `user@host ~/path > `
Type `exit` to quit or `cd` to change directories.
## How a shell works (general)
At a high level, most shells follow the REPL loop (Read-eval-print):
1. Read
- Display a prompt and read a line of input from the terminal (stdin).
- Parse: Split the input into a program name and its arguments. Full shells also handle quoting, escaping,
variable expansion, globbing, pipelines (`|`), redirections (`>`, `<`, `>>`), and subshells.
This project intentionally keeps parsing simple (whitespace-separated tokens) to stay readable.
2. Eval (evaluate the input)
- Decide what “the command” refers to:
- Builtin: a command implemented inside the shell process (e.g., `cd`, which must change the current process working directory).
- External: an executable resolved via `PATH` (e.g., `/usr/bin/ls`).
3. Print (execute and print output)
- Builtins: run a function in the current process.
- External: fork/exec (in Go: create an `exec.Cmd` and call `Run`), wiring stdin/stdout/stderr so output appears in your terminal.
- Capture or propagate the exit status to use in conditionals and the next prompt.
Beyond the basics (not all implemented here):
- Redirections and pipes connect processes via file descriptors.
- Job control manages foreground/background processes and signals (CtrlC, CtrlZ).
- Shell scripting adds variables, conditionals, loops, and functions.
## Project architecture
Executable
- `cmd/gosh`: main program. REPL code (Read-eval-print loop)
Core packages
- `internal/runner`: command resolver and executor. Runs either a builtin or an external program.
- `internal/parser`: turns raw input into a `command.Definition` (a simple `[]string`).
- `internal/command`: helpers around command name/args.
- `internal/builtins`: builtin registry and implementations (currently `cd`, `exit`).
Supporting packages
- `internal/prompt`: expands prompt variables like `%u` (user), `%h` (host), `%w` (cwd).
- `internal/paths`: home-directory lookup, `~` expansion, and home abbreviation.
## Prompt format
The prompt string is defined in `cmd/gosh/gosh.go` and supports:
- `%u` → current user
- `%h` → hostname
- `%w` → working directory (**with** home abbreviated to `~`)
- `%W` → working directory (**without** home abbreviated to `~`)
## Example session
```
$ go run ./cmd/gosh
me@myhost ~ > pwd
/home/me
me@myhost ~ > cd /tmp
me@myhost /tmp > ls
...
me@myhost /tmp > exit 0
```
## Learning roadmap (ideas to extend)
- Input
- Support multi-line inputs.
- Parsing
- Quoting and escaping (single quotes, double quotes, backslash)
- Environment variable expansion (`$HOME`, `${VAR}`)
- Globbing (`*`, `?`, `[]`)
- Execution
- PATH resolution with helpful errors and `which`-like behavior
- Redirections (`>`, `>>`, `<`) and pipelines (`|`)
- Background jobs (`cmd &`) and job control (fg/bg, signals)
- UX
- Command history and line editing
- Configurable prompts/themes
## Status
This is intentionally minimal and focused on readability.
If you experiment or extend it, consider adding tests close to the code you change
(e.g., for `paths` and parsing behavior) to keep the learning loop tight.