Continuing the theme of exploring Go Lang, today I will be writing a simple version of the Unix utility wc that displays the number of lines, words, and bytes contained in each input file.

This exploration process will involve the following pieces

  • Getting a file name from command line. os
  • Opening the file for reading. os
  • Reading the contents of the file. bufio
  • Count the lines, words and bytes. unicode
  • Display the results.

1. Read filename from the commandline Link to heading

Any arguments typed after the programs named are passed into the os.Args array with the name of the program accessible at the first index.

var fileName string
if len(os.Args) > 1 {
    fileName = os.Args[1]
} else {
    fmt.Println("Please pass a file name")
    os.Exit(1)
}

2. Open the file Link to heading

Once you have the name of the file, it can be simply opened using the "os.Open()" function in the os package. If the open fails, the error string will be self-explanatory.

file, err := os.Open(fileName)
if err != nil {
    fmt.Println("Err ", err)
}

#🤓 Explore the os package as part of getting familiar with Go Lang.

3. Read the contents of the file Link to heading

There are quite a few ways of reading the contents of the file. In this post I will be using the bufio package to read the contents of the file line by line using NewScanner().

In the code snippet below, we are scanning the file line by line and printing the output to the console.

scanner := bufio.NewScanner(file)
lines, words, characters := 0, 0, 0
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

4. Analyze the file content Link to heading

Finally, we need to keep track of the lines in the file, and the number or words in each line.

The total byte/characters will be the summation of length of each line we iterate while reading the file. And to compute the number of words we can simply split the line based on whitespace and count the total number of such splits.

scanner := bufio.NewScanner(file)
lines, words, characters := 0, 0, 0
for scanner.Scan() {
    lines++

    line := scanner.Text()
    characters += len(line)

    splitLines := strings.Split(line, " ")
    words += len(splitLines)
}

4. Display Link to heading

Once, we have compute the word count, it can be displayed on the cosole using the fmt.

fmt.Printf("%8d%8d%8d %s\n", lines, words, characters, fileName)

Full program listing Link to heading

This is the complete listing of the program implementing the WC utility in Go Lang.

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
    var fileName string
    if len(os.Args) > 1 {
        fileName = os.Args[1]
    } else {
        fmt.Println("Please pass a file name")
        os.Exit(1)
    }
    file, err := os.Open(fileName)
    if err != nil {
        fmt.Println("Err ", err)
    }
    scanner := bufio.NewScanner(file)
    lines, words, characters := 0, 0, 0
    for scanner.Scan() {
        lines++

        line := scanner.Text()
        characters += len(line)

        splitLines := strings.Split(line, " ")
        words += len(splitLines)
    }
    fmt.Printf("%8d%8d%8d %s\n", lines, words, characters, fileName)
}

#🤓 Explore the wc utility and try to finish up the missing pieces.