Skip to content

Commit d59697e

Browse files
committed
Added 'find' sub-command.
1 parent a0a2f7f commit d59697e

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,22 @@ For examples please consult the output of `sysbox help expect`, but a simple exa
217217
```
218218

219219

220+
## find
221+
222+
The find sub-command allows finding files/directories that match a given number
223+
of regular expressions. Basic usage is:
224+
225+
$ sysbox find foo bar$
226+
227+
By default the names of files are shown, but you can view either files, directories, or both. The starting point will be the current working directory, but `-path` can be used to change that:
228+
229+
$ sysbox find -path /etc -files=true -directories=true '(i?)magic'
230+
/etc/ImageMagick-6/magic.xml
231+
/etc/magic
232+
/etc/magic.mime
233+
/etc/sane.d/magicolor.conf
234+
235+
220236
## fingerd
221237

222238
A trivial finger-server.

cmd_find.go

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"regexp"
9+
)
10+
11+
// Structure for our options and state.
12+
type findCommand struct {
13+
14+
// Show the names of matching directories?
15+
directories bool
16+
17+
// Show the names of matching files?
18+
files bool
19+
20+
// Starting path
21+
path string
22+
23+
// Ignore errors?
24+
silent bool
25+
}
26+
27+
// Info returns the name of this subcommand.
28+
func (fc *findCommand) Info() (string, string) {
29+
return "find", `Trivial file-finder.
30+
31+
Details:
32+
33+
This command is a minimal 'find' replacement, allowing you to find
34+
files by regular expression. Basic usage defaults to finding files,
35+
by regular expression:
36+
37+
$ sysbox find 'foo*.go' '_test'
38+
39+
To find directories instead of files:
40+
41+
$ sysbox find -files=false -directories=true 'blah$'
42+
43+
Or both:
44+
45+
$ sysbox find -path=/etc -files=true -directories=true 'blah$'
46+
`
47+
}
48+
49+
// Arguments adds per-command args to the object.
50+
func (fc *findCommand) Arguments(f *flag.FlagSet) {
51+
f.BoolVar(&fc.files, "files", true, "Show the names of matching files?")
52+
f.BoolVar(&fc.directories, "directories", false, "Show the names of matching directories?")
53+
f.BoolVar(&fc.silent, "silent", true, "Ignore permission-denied errors when recursing into unreadable directories?")
54+
f.StringVar(&fc.path, "path", ".", "Starting path for search.")
55+
}
56+
57+
// find runs the find operation
58+
func (fc *findCommand) find(patterns []string) error {
59+
60+
// build up a list of regular expressions
61+
regs := []*regexp.Regexp{}
62+
63+
for _, pattern := range patterns {
64+
65+
reg, err := regexp.Compile(pattern)
66+
if err != nil {
67+
return fmt.Errorf("failed to compile %s:%s", pattern, err)
68+
}
69+
70+
regs = append(regs, reg)
71+
}
72+
73+
//
74+
// Walk the filesystem
75+
//
76+
err := filepath.Walk(fc.path,
77+
func(path string, info os.FileInfo, err error) error {
78+
if err != nil {
79+
if !os.IsPermission(err) {
80+
return err
81+
}
82+
83+
if !fc.silent {
84+
fmt.Fprintln(os.Stderr, "permission denied handling "+path)
85+
}
86+
}
87+
88+
// We have a path.
89+
//
90+
// If it doesn't match any of our regexps then we return.
91+
//
92+
// i.e. We must match ALL supplied patterns, not just
93+
// one of them.
94+
//
95+
for _, r := range regs {
96+
if !r.MatchString(path) {
97+
return nil
98+
}
99+
}
100+
101+
// is it a file?
102+
isDir := info.IsDir()
103+
isFile := !isDir
104+
105+
if (isDir && fc.directories) ||
106+
(isFile && fc.files) {
107+
fmt.Printf("%s\n", path)
108+
}
109+
return nil
110+
})
111+
112+
if err != nil {
113+
return fmt.Errorf("error walking filesystem %s", err)
114+
}
115+
116+
return nil
117+
}
118+
119+
// Execute is invoked if the user specifies `find` as the subcommand.
120+
func (fc *findCommand) Execute(args []string) int {
121+
122+
//
123+
// Build up the list of patterns
124+
//
125+
patterns := []string{}
126+
for _, arg := range args {
127+
patterns = append(patterns, arg)
128+
}
129+
130+
//
131+
// Ensure we have a least one.
132+
//
133+
if len(patterns) < 1 {
134+
fmt.Printf("Usage: sysbox find pattern1 [pattern2..]\n")
135+
return 1
136+
}
137+
138+
//
139+
// Run the find.
140+
//
141+
err := fc.find(patterns)
142+
if err != nil {
143+
fmt.Printf("%s\n", err)
144+
return 1
145+
}
146+
147+
//
148+
// All done
149+
//
150+
return 0
151+
}

main.go

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func main() {
4444
subcommands.Register(&envTemplateCommand{})
4545
subcommands.Register(&expectCommand{})
4646
subcommands.Register(&execSTDINCommand{})
47+
subcommands.Register(&findCommand{})
4748
subcommands.Register(&fingerdCommand{})
4849
subcommands.Register(&html2TextCommand{})
4950
subcommands.Register(&httpdCommand{})

0 commit comments

Comments
 (0)