-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #27. Basic features of grep including line numbers, stdin, files, case insensitivity, and inversion are supported. Additionally, I've refactored base to support the common pattern of running for multiple files or stdin if none are specified. This may cause a refactor in `wc`, and `cat` -- possibly others.
- Loading branch information
1 parent
e0bfcd4
commit 5f08a52
Showing
2 changed files
with
125 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package commands | ||
|
||
import ( | ||
"bufio" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"regexp" | ||
|
||
"github.com/josephlewis42/honeyssh/core/vos" | ||
) | ||
|
||
// Grep implements the POSIX grep command. | ||
// | ||
// https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/ | ||
func Grep(virtOS vos.VOS) int { | ||
cmd := &SimpleCommand{ | ||
Use: "grep [-iv] PATTERN [FILE]...", | ||
Short: "Search files for text matching a pattern.", | ||
} | ||
|
||
invert := cmd.Flags().Bool('v', "Select lines not matching any of the specified patterns.") | ||
ignoreCase := cmd.Flags().Bool('i', "Perform pattern matching in searches without regard to case.") | ||
showLineNumbers := cmd.Flags().Bool('n', "Show line numbers.") | ||
|
||
return cmd.Run(virtOS, func() int { | ||
args := cmd.Flags().Args() | ||
if len(args) == 0 { | ||
cmd.LogProgramError(virtOS, errors.New("missing argument PATTERN")) | ||
return 1 | ||
} | ||
|
||
// NOTE: Officially, the PATTERN argument supports multiple patterns delimited by newlines. | ||
// It's a very rare case so we'll ignore it here. | ||
pattern := args[0] | ||
if *ignoreCase { | ||
pattern = "(?i)" + pattern | ||
} | ||
regex, err := regexp.Compile(pattern) | ||
if err != nil { | ||
cmd.LogProgramError(virtOS, err) | ||
return 2 | ||
} | ||
|
||
files := args[1:] | ||
showFileName := len(files) > 1 | ||
return cmd.RunEachFileOrStdin(virtOS, files, func(name string, fd io.Reader) error { | ||
w := virtOS.Stdout() | ||
|
||
scanner := bufio.NewScanner(fd) | ||
lineNo := 1 | ||
for scanner.Scan() { | ||
line := scanner.Bytes() | ||
lineMatches := regex.Match(line) | ||
|
||
// Write output | ||
if (lineMatches && !*invert) || (!lineMatches && *invert) { | ||
if showFileName { | ||
fmt.Fprintf(w, "%s:", name) | ||
} | ||
|
||
if *showLineNumbers { | ||
fmt.Fprintf(w, "%d:", lineNo) | ||
} | ||
|
||
fmt.Fprintf(w, "%s\n", line) | ||
} | ||
lineNo++ | ||
} | ||
|
||
return nil | ||
}) | ||
}) | ||
} | ||
|
||
var _ vos.ProcessFunc = Grep | ||
|
||
func init() { | ||
addBinCmd("grep", Grep) | ||
} |