Video Coming Soon...
46: find
The final project in this module is find. Find is a very useful tool that searches through a directory of files--and its children--that match specific patterns. It does a lot more than that though. With find you can do the following (to name a few):
- Find all the files matching a certain regex.
- Print them out or...
- run any command you want on them.
- Or, only process directories that match the regex, or only files.
It does quite a lot, so that's why it's the last project. You could go insane making everything in find work, and I highly recommend you spend some time making the most awesome find possible.
The Challenge
I think find is a little tricky because Go flag package can't really do what find needs. You can get close enough, but at a certain point you'll need to not use flag go out on your own. Other than that find uses most of what you've learned so far, and should be a good final project.
Here's the documentation for find:
Requirements
Nothing new here, you've used all of this:
See the list of requirements
- fmt -- https://pkg.go.dev/fmt
- flag -- https://pkg.go.dev/flag
- path/filepath -- https://pkg.go.dev/path/filepath
- regexp -- https://pkg.go.dev/regexp
- log -- https://pkg.go.dev/log
- io/fs -- https://pkg.go.dev/io/fs
Spoilers
My version of find is very simple. I only find files of type d and f, and I only match on regex recursively. Can you do better?
See my first version code
View Source file go-coreutils/find/main.go Onlypackage main
import (
"fmt"
"flag"
"path/filepath"
"regexp"
"log"
"io/fs"
)
type Opts struct {
Name string
Type string
}
func ParseOpts() Opts {
var opts Opts
flag.StringVar(&opts.Name, "name", "", "regex of file")
flag.StringVar(&opts.Type, "type", "f", "type to find")
flag.Parse()
if flag.NArg() == 0 {
log.Fatal("USAGE: find -name <regex> [-type d/f] <dir> [dir dir]")
}
return opts
}
func main() {
opts := ParseOpts()
re, err := regexp.Compile(opts.Name)
if err != nil { log.Fatal(err) }
for _, start := range flag.Args() {
filepath.WalkDir(start, func (path string, d fs.DirEntry, err error) error {
if err != nil { log.Fatal(err) }
if re.MatchString(path) {
if opts.Type == "" {
fmt.Println(path)
} else if d.IsDir() && opts.Type == "d" {
fmt.Println(path)
} else if !d.IsDir() && opts.Type == "f" {
fmt.Println(path)
}
}
return nil
})
}
}
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.
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.