Shows how to build small CLI tools in Python, Go, and C++ with runnable examples including a project generator, Vue demo, CSV to JSON converter, and a password generator
In this lesson we build several small, focused CLI utilities to show how quickly useful command-line tools can be scaffolded in different languages. The examples alternate between Python, Go, and C++ to demonstrate differences in ergonomics, deployment, and performance. Each example includes a runnable implementation, usage examples, and notes on why you might pick one language over another for a particular task.Table of contents:
Goal: create a small Python CLI script, project_generator.py, that generates boilerplate project folders in a dist/ directory. This generator keeps things simple and file-system focused — no external dependencies required.Supported project types:
html — generates index.html, style.css, and scripts.js
What you get: running the HTML generator creates a small styled page with a hero section and a button wired to scripts.js. This is a simple, editable starting point suitable for demos or rapid prototyping.
Test the generator’s help and argument validation:
The Vue-style generator produces a minimal client-side demo: a counter and a tiny todo list implemented in plain JavaScript. The intent is demonstration, not a full Vue build pipeline — you can later migrate the generated files to a modern Vue project if you want to add components, bundling, or state management.Test and extend:
Open dist/<project>/index.html in a browser to interact with the demo.
Edit app.js to add features, then port into a Vue CLI / Vite setup if you need a build toolchain.
Goal: implement a small Go CLI (example name csv-to-json or main.go) that reads data/contacts.csv and outputs JSON to stdout. Add a -limit flag to restrict the number of returned records. If -limit is omitted, return all records.Usage:
Copy
# All recordsgo run main.go# Limit to first 5 recordsgo run main.go -limit=5# Specify an alternative CSV filego run main.go -file=other.csv -limit=10
Concise main.go example:
Copy
package mainimport ( "encoding/csv" "encoding/json" "flag" "fmt" "io" "os" "strconv")type Contact struct { ID int `json:"id"` FirstName string `json:"first_name"` LastName string `json:"last_name"` JobTitle string `json:"job_title"` Email string `json:"email"`}func main() { limit := flag.Int("limit", 0, "limit number of records (0 = all)") csvPath := flag.String("file", "data/contacts.csv", "path to CSV file") flag.Parse() f, err := os.Open(*csvPath) if err != nil { fmt.Fprintf(os.Stderr, "Error opening CSV file: %v\n", err) os.Exit(1) } defer f.Close() r := csv.NewReader(f) // Read header headers, err := r.Read() if err != nil { fmt.Fprintf(os.Stderr, "Error reading header: %v\n", err) os.Exit(1) } _ = headers // header names are known in this format var contacts []Contact for { if *limit > 0 && len(contacts) >= *limit { break } record, err := r.Read() if err == io.EOF { break } if err != nil { fmt.Fprintf(os.Stderr, "Error reading record: %v\n", err) os.Exit(1) } id, _ := strconv.Atoi(record[0]) contacts = append(contacts, Contact{ ID: id, FirstName: record[1], LastName: record[2], JobTitle: record[3], Email: record[4], }) } enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") if err := enc.Encode(contacts); err != nil { fmt.Fprintf(os.Stderr, "Error encoding JSON: %v\n", err) os.Exit(1) }}
Notes:
This example assumes a CSV header id,first_name,last_name,job_title,email.
Flags: -limit to cap results and -file to point to another CSV.
The program pretty-prints JSON to stdout so you can pipe or redirect it easily.
Example commands:
Copy
# Show first 3 recordsgo run main.go -limit=3# All records (may be many) — pipe through `head` if you want a previewgo run main.go | head -n 20
Why Go for small CLIs:
Single static binary output (deployable without runtime)
Goal: build passgen, a small C++ CLI that emits secure-looking passwords. Options:
-l, --length (default 16)
-c, --count (how many passwords to print)
--no-symbols (omit symbol characters)
--help
Important security note: this example seeds a PRNG using std::random_device and uses std::mt19937. std::mt19937 is fast and suitable for many tasks, but it is not cryptographically secure. For production-grade passwords, use an OS-provided CSPRNG (e.g., arc4random_buf on BSD/macOS or getrandom on Linux) or a dedicated crypto library.
This example uses std::mt19937 seeded with std::random_device. For production-grade cryptographic passwords, use an OS-provided CSPRNG or a cryptographic library (std::mt19937 is not cryptographically secure).
Automation: batch process files, convert formats, and apply transformations programmatically.
CI/CD integration: use micro-utilities for formatting, validation, conversion (CSV → JSON), and other pipeline tasks.
Portability: compiled tools (Go/C++) can be easily distributed as single binaries; scripts (Python) are quick to iterate on.
This lesson demonstrates that small, well-scoped CLIs can be created quickly and evolve into production-grade tools with additions like testing, logging, packaging, and secure random sources.If you want any example expanded — for example, unit tests for the Python generator, a packaged Go binary with module setup, or a C++ version that uses OS CSPRNG APIs — tell me which one and I’ll add the details.