Simple Grep CLI in Go
A small Go program that searches a file line by line for a substring and prints matching lines with their line numbers, skipping binary files.
Project
go-grep-cli
Entry point: main.go
Install
go versionRun
go run main.go notes.txt TODOTest
go run main.go notes.txt TODOExpected output
Prints each matching line prefixed by its line number, or nothing when there is no match.Dependencies
- go >=1.21
What it does
A minimal grep that streams a file line by line with bufio, so it works on files larger than memory and exits with the conventional status codes.
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
if len(os.Args) != 3 {
fmt.Fprintln(os.Stderr, "usage: grep <file> <pattern>")
os.Exit(2)
}
path, pattern := os.Args[1], os.Args[2]
file, err := os.Open(path)
if err != nil {
fmt.Fprintln(os.Stderr, "open error:", err)
os.Exit(2)
}
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024)
line := 0
matched := false
for scanner.Scan() {
line++
text := scanner.Text()
if strings.Contains(text, pattern) {
fmt.Printf("%d: %s\n", line, text)
matched = true
}
}
if !matched {
os.Exit(1)
}
}
It reads with a scanner that has a raised line-length limit, which avoids the default sixty-four kilobyte line ceiling.
Run and verify
go run main.go notes.txt TODO
Run against a text file with the pattern as the second argument; exit codes follow grep convention.
Expected Output
For a file whose second line contains the pattern the program should print that line with its number. The output is:
2: TODO: write the release notes
Matching lines print with their one-based line number, no match exits with status one, and a usage error exits with status two.
Limitations
It is a fixed substring search, not a regular expression engine; a regex version would compile the pattern and scan per match.