CodeBlanks Logo Icon CodeBlanks

Challenge 4 - CLI tool

Write a CLI tool that processes files with flag.

Challenge: a line-counting tool

You will write a CLI tool similar to Unix wc. Rules: with -l it prints only the line count; without it, the line, word and byte counts. Input is read from stdin; so it can be tested, all logic lives in a run(args, in, out) function.

printf "a b\nc\n" | ./say       # 2 3 6
printf "a b\nc\n" | ./say -l    # 2

Plan

1) A -l bool option with a FlagSet. 2) veri, err := io.ReadAll(in). 3) Lines: bytes.Count(veri, []byte("\n")); words: len(strings.Fields(string(veri))); bytes: len(veri). 4) With -l write only the line count, otherwise all three with fmt.Fprintln(out, ...). 5) In main, on error write to stderr and os.Exit(1).

Practice Write the tool

Implement the plan. In main, call run(nil, strings.NewReader("a b\nc\n"), os.Stdout) and run([]string{"-l"}, strings.NewReader("a b\nc\n"), os.Stdout).

Starter code

main.go
package main

import (
    "bytes"
    "flag"
    "fmt"
    "io"
    "os"
    "strings"
)

func main() {
    // buraya yaz
}

Sample solution

main.go
package main

import (
    "bytes"
    "flag"
    "fmt"
    "io"
    "os"
    "strings"
)

func run(args []string, in io.Reader, out io.Writer) error {
    fs := flag.NewFlagSet("say", flag.ContinueOnError)
    l := fs.Bool("l", false, "yalnızca satır sayısı")
    if err := fs.Parse(args); err != nil {
        return err
    }
    veri, err := io.ReadAll(in)
    if err != nil {
        return err
    }
    lines := bytes.Count(veri, []byte("\n"))
    if *l {
        _, err = fmt.Fprintln(out, lines)
        return err
    }
    _, err = fmt.Fprintln(out, lines, len(strings.Fields(string(veri))), len(veri))
    return err
}

func main() {
    for _, a := range [][]string{nil, {"-l"}} {
        if err := run(a, strings.NewReader("a b\nc\n"), os.Stdout); err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }
    }
}

Expected output

2 3 6
2

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Which gives the byte count most accurately?

  • utf8.RuneCount
  • Read all input and take len(veri) Correct answer
  • Summing the line lengths
  • Word count × 5

Explanation: A Scanner drops line endings, so summing line lengths misses the \n bytes. RuneCount counts characters, not bytes.

2 Count the lines

Question
lines := bytes.____(veri, []byte("
"))
Answer
lines := bytes.Count(veri, []byte("
"))

Explanation: bytes.Count counts how many times a subslice appears; the number of newlines is the line count.

3 Measurement and method

Term Meaning
Line bytes.Count(\n)
Kelime strings.Fields
Bayt len(veri)
Karakter utf8.RuneCount

All lessons in Intermediate