commit 317e69024bbd29c25650619df93fbdbe9bea9cf9 Author: Adriano Caloiaro Date: Mon Sep 23 22:13:29 2019 -0400 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..ef35b18 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# struct + +A simple unix utility for structuring string data on the command line. + +# example usage + +## string output +``` +$ ls -l | struct -fields permissions,count,user,group,,,,,file_name -output string +permissions:-rw-r--r-- count:1 user:adriano group:staff 84 Sep 23 22:55 file_name:README.md +permissions:-rw------- count:1 user:adriano group:staff 39 Sep 23 21:08 file_name:go.mod +permissions:-rw-r--r-- count:1 user:adriano group:staff 2531 Sep 23 22:54 file_name:struct.go +``` + +## json output + +```bash +$ ls -l | struct -fields permissions,count,user,group,,,,,file_name -output json +{"count":"1","file_name":"README.md","group":"staff","permissions":"-rw-r--r--","user":"adriano"} +{"count":"1","file_name":"go.mod","group":"staff","permissions":"-rw-------","user":"adriano"} +{"count":"1","file_name":"struct.go","group":"staff","permissions":"-rw-r--r--","user":"adriano"} +``` diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..44027b2 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module adriano.fyi/pkg/struct + +go 1.12 diff --git a/struct.go b/struct.go new file mode 100644 index 0000000..a09b90c --- /dev/null +++ b/struct.go @@ -0,0 +1,145 @@ +package main + +import ( + "bufio" + "encoding/json" + "errors" + "flag" + "fmt" + "os" + "strings" +) + +type fields []string + +var fieldsFlag fields +var sepFlag string +var outFlag string + +var in string +var fieldsProvided int + +func (f *fields) String() string { + return fmt.Sprint(*f) +} + +func (f *fields) Set(value string) error { + if len(*f) > 0 { + return errors.New("fields switch already set") + } + + for _, field := range strings.Split(value, ",") { + *f = append(*f, field) + } + + return nil +} + +const ( + defaultFieldSeparator = " " + defaultOutput = "string" + fieldsUsage = "comma-separated list of fields corresponding to the input data's fields\n\n" + + "Example\n\n" + + "$ echo \"foo1 bar1\" | struct -fields foo,bar\n" + + "$ foo:foo1 bar:bar1\n" + outputUsage = "the desired output format: json or string" + separatorUsage = "the character that separates fields in the input data" +) + +func init() { + + flag.Var(&fieldsFlag, "fields", fieldsUsage) + flag.StringVar(&sepFlag, "separator", defaultFieldSeparator, separatorUsage) + flag.StringVar(&outFlag, "output", defaultOutput, outputUsage) + setupFlags(flag.CommandLine) + + flag.Parse() +} + +func setupFlags(f *flag.FlagSet) { + f.Usage = func() { + fmt.Println("\nCreate structured data input strings") + + f.PrintDefaults() + } +} + +var sb strings.Builder +var jsonMap = make(map[string]string) + +func main() { + fieldsProvided = len(fieldsFlag) + + scanner := bufio.NewScanner(os.Stdin) + + var i int + var field, v string + + for scanner.Scan() { + in = scanner.Text() + + inputFields := strings.Fields(in) + + for i, v = range inputFields { + if i < fieldsProvided { + + field = fieldsFlag[i] + } else { + field = "" + } + + buildOutput(field, v) + } + + fmt.Println(out()) + } +} + +func out() (out string) { + if outFlag == "string" { + out = sb.String() + sb.Reset() + } else if outFlag == "json" { + o, _ := json.Marshal(jsonMap) + out = string(o) + for k := range jsonMap { + delete(jsonMap, k) + } + } else { + out = "" + } + + return +} + +func buildOutput(field, value string) error { + if outFlag == "string" { + buildString(field, value) + } else if outFlag == "json" { + buildJSON(field, value) + } else { + return errors.New("invalid output option") + } + + return nil +} + +func buildString(field, value string) { + if field != "" { + sb.WriteString(field) + sb.WriteString(":") + sb.WriteString(value) + sb.WriteString(sepFlag) + } else { + sb.WriteString(value) + sb.WriteString(sepFlag) + } +} + +func buildJSON(field, value string) { + if field == "" { + return + } + + jsonMap[field] = value +}