019 Project 19: Linux ps-lite
019 Build a Linux ps-Lite Tool
Read process info from /proc and print a compact process table.
/proc -> parse /proc/<pid>/stat + comm -> rows -> sort by pid -> table
Full main.go
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
)
type proc struct {
PID int
Comm string
RSS int64
State string
}
func parseProc(pid int) (proc, error) {
statPath := fmt.Sprintf("/proc/%d/stat", pid)
b, err := os.ReadFile(statPath)
if err != nil {
return proc{}, err
}
parts := strings.Fields(string(b))
if len(parts) < 24 {
return proc{}, fmt.Errorf("short stat")
}
comm := strings.Trim(parts[1], "()")
state := parts[2]
rssPages, _ := strconv.ParseInt(parts[23], 10, 64)
return proc{PID: pid, Comm: comm, State: state, RSS: rssPages * 4096}, nil
}
func main() {
limit := flag.Int("n", 50, "max rows")
flag.Parse()
entries, err := os.ReadDir("/proc")
if err != nil {
fmt.Println("/proc unavailable (Linux only)")
os.Exit(1)
}
var rows []proc
for _, e := range entries {
if !e.IsDir() {
continue
}
pid, err := strconv.Atoi(e.Name())
if err != nil {
continue
}
p, err := parseProc(pid)
if err == nil {
rows = append(rows, p)
}
}
sort.Slice(rows, func(i, j int) bool { return rows[i].PID < rows[j].PID })
if *limit > len(rows) {
*limit = len(rows)
}
fmt.Printf("%-8s %-4s %-10s %s\n", "PID", "S", "RSS(MB)", "COMM")
for i := 0; i < *limit; i++ {
r := rows[i]
fmt.Printf("%-8d %-4s %-10.1f %s\n", r.PID, r.State, float64(r.RSS)/1024.0/1024.0, filepath.Base(r.Comm))
}
}Run
go run . -n 40Step-by-Step Explanation
- Parse command-line flags and validate inputs early.
- Keep the core operation in a small, testable function.
- Process data as a stream when possible to reduce memory use.
- Print stable output and meaningful exit codes.
- Add one extension feature and test edge cases.
Code Anatomy
mainhandles flags, orchestration, and errors.- Worker/helper functions hold business logic.
- Output section should be deterministic for scripting and CI usage.
Learning Goals
- Write composable Unix-style Go tools.
- Improve error messages and operator experience.
- Practice iterative improvement over one clear baseline.