Video Coming Soon...

Created by Zed A. Shaw Updated 2025-11-14 00:08:54

38: stat Then du

You've had 7 exercises of easy commands, so now you're going to do two related more complex commands. The first one is stat, which gives you information on a file. The second is du which gives you "disk usage" information, or how much of your disk is used by each directory.

The Challenge

The most important thing to learn from this lesson is getting "meta-data" from files, and walking a directory. Walking the directory happens in the du utility, and it means to start at the top of a directory tree and visit every child directory and file.

Go has several equally annoying ways to walk a directory structure, so I'll just tell you to use filepath.WalkDir. There are about 3-4 other ways but this one is the easiest to use.

You'll also be required to use an anonymous function when you use filepath.WalkDir.

The documentation for these commands are:

Requirements

Before you peek, remember that you'll need path/filepath.WalkDir to implement du.

See the list of requirements

The stat Code

You should start with stat as it's the simplest and du does a stat on all the files in a directory. My stat is simple enough to fit in the main():

See my first version of statView Source file go-coreutils/stat/main.go Only

package main

import (
  "fmt"
  "os"
  "flag"
  "log"
  "io/fs"
)

func PrintStat(stat fs.FileInfo) {
  fmt.Printf("File: %s\nSize: %d\nAccess: %v\nModify: %v",
  stat.Name(),
  stat.Size(),
  stat.Mode(),
  stat.ModTime())
}

func main() {
  flag.Parse()
  files := flag.Args()

  for _, fname := range files {
    f, err := os.Open(fname)
    if err != nil { log.Fatal(err) }
    defer f.Close()

    stats, err := f.Stat()
    if err != nil { log.Fatal(err) }

    PrintStat(stats)
  }
}

The du Code

The du command is more complicated as it needs to walk a whole directory tree. I think they key thing to study here is how I use an anonymous function to analyze the results of filepath.WalkDir():

See my first version of duView Source file go-coreutils/du/main.go Only

package main

import (
  "fmt"
  "log"
  "flag"
  "io/fs"
  "path/filepath"
)

func StatDir(target_path string) error {
  var cur_dir string
  var cur_size int64

  // NOTE: cover the difference betweeen filepath.WalkDir and fs.WalkDir

  err := filepath.WalkDir(target_path, func (path string, d fs.DirEntry, err error) error {
    if d.IsDir() {
      if cur_dir != path {
        loc := filepath.Join(target_path, cur_dir)
        fmt.Printf("%s %d\n", loc, cur_size / 1024)
        cur_dir = path
        cur_size = 0
      }
    } else {
      info, err := d.Info()
      if err != nil { return nil }
      cur_size += info.Size()
    }

    return nil
  })

  return err
}

func main() {
  flag.Parse()
  paths := flag.Args()

  for _, path := range paths {
    err := StatDir(path)
    if err != nil { log.Fatal(err) }
  }
}

Testing It

If you want to push your learning further then you can try to implement an automated test for this. I actually need to learn how to test utilities like this with Go, so for now just consider this an extra challenge for later until I learn how to teach it.

Previous Lesson Next Lesson

Register for Learn Go the Hard Way

Register today for the course and get the all currently available videos and lessons, plus all future modules for no extra charge.