← Runnable Projects

阅读中文版本

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.

beginnergounverified

Project

go-grep-cli

Entry point: main.go

Install

go version

Run

go run main.go notes.txt TODO

Test

go run main.go notes.txt TODO

Expected 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.