Skip subdirectories with filepath.Walk

6,494 views
Skip to first unread message

Archos

unread,
Mar 11, 2012, 4:21:02 PM3/11/12
to golang-nuts
I'm using the next code to looking for some files by its extension.
But I've some doubts:

1) I've to use a global variable to store the values got in search().
Could be used a local variable to return in walkDir()?

2) Is there any way to skip a full subdirectory? The only way that
I've found is to checking the path to see if the subdirectory to skip
is in the path but it has to checked for each path so its performance
is not very good

By example, to checking hidden directories:

./foo/
./bar/
./.git/ // it would be found
./.git/a.txt // it would be found
./.git/b.txt // it would be found
./doc/

But I would want that, when ".git" is found, then the next path were
"doc"


// * * *
package main

import (
"fmt"
"os"
"path/filepath"
"strings"
)

var paths = make([]string, 0)

func walkDir(path string) {
errors := make(chan error)
done := make(chan bool)

// Error handler
go func() {
for err := range errors {
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err) // TODO: send to a file
}
}
done <- true
}()

//fmt.Printf(" + Checking: %q...\n", path)
filepath.Walk(path, search(errors))
close(errors)
<-done
fmt.Println()
}

// Search files with ".go~" extension.
func search(errors chan error) filepath.WalkFunc {
// Implements "filepath.WalkFunc".
return func(path string, info os.FileInfo, err error) error {
if err != nil {
errors <- err
return nil
}

if info.IsDir() {
fmt.Printf(" + checking: %q\n", path)
}

// Skip directories ang hidden files
if info.IsDir() || filepath.HasPrefix(info.Name(), ".") {
return nil
}

fileExt := strings.ToLower(filepath.Ext(info.Name()))
if fileExt == ".go~" {
paths = append(paths, path)
}

return nil
}
}

func main() {
walkDir("/home/neo/go/src/github.com/kless/GoWizard")
fmt.Println(paths)
}
// * * *

Rémy Oudompheng

unread,
Mar 11, 2012, 4:59:16 PM3/11/12
to Archos, golan...@googlegroups.com
On Sun 11 March 2012 at 13:21 -0700, Archos wrote:
> I'm using the next code to looking for some files by its extension.
> But I've some doubts:
>
> 1) I've to use a global variable to store the values got in search().
> Could be used a local variable to return in walkDir()?

Not sure what you want to do. A closure should solve your problem.

> 2) Is there any way to skip a full subdirectory? The only way that
> I've found is to checking the path to see if the subdirectory to skip
> is in the path but it has to checked for each path so its performance
> is not very good

You have to return a special value has specified in the documentation.
You can read existing uses of filepath.Walk in the standard
library/commands to find patterns.

--
R�my.

Hotei

unread,
Mar 11, 2012, 5:54:56 PM3/11/12
to golan...@googlegroups.com, Archos, remyoud...@gmail.com
I ran into the same thing a while back.  The goal in my case is specifically to NOT process anything that lives in a .git repository.  Everything else is fair game.  I put it on back burner but would be interested if someone has already produces a solution.

--
R�my.

Archos

unread,
Mar 11, 2012, 7:04:26 PM3/11/12
to golang-nuts
For your case:

if info.IsDir() && info.Name() == ".git" {
return filepath.SkipDir

Mike Rosset

unread,
Mar 12, 2012, 6:42:41 AM3/12/12
to Archos, golang-nuts

I think what you are looking for is filepath.SkipDir. I added an
example for this in go1.html see
http://weekly.golang.org/doc/go1.html#path_filepath

Reply all
Reply to author
Forward
0 new messages