3

How do I take a string and parse it as if it was a series of command line arguments? I want to be able to take a string and parse that with flag and/or pflag. How do I do this?

package main

import (
    "fmt"
    "os"

    flag "github.com/spf13/pflag"
)

func main() {
    command := `unimportant -fb "quoted string"`
    var (
        foo bool
        bar string
    )
    flag.BoolVarP(&foo, "foo", "f", false, "foo")
    flag.StringVarP(&bar, "bar", "b", "default", "bar")

    // Parse command
    os.Args = append(os.Args, "-fb", "quoted string")
    flag.Parse()

    fmt.Println(command)
    fmt.Println("foo", foo)
    fmt.Println("bar", bar)
}
0

2 Answers 2

4

The easiest way would be use the package shellwords to parse your string into an argv of shell words, and then use a command-line parser other than flag or pflag that supports parsing an arbitrary argv (say flags, but there are many to choose from.)

// Parse  your string into an []string as the shell would.

argv, err := shellwords.Parse("./foo --bar=baz")
// argv should be ["./foo", "--bar=baz"]

...

// define your options, etc. here

...

extraArgs, err := flags.ParseArgs(&opts, argv)
Sign up to request clarification or add additional context in comments.

3 Comments

flag and pflag can both parse an arbitrary argv, see flag.FlagSet.Parse and pflag.FlagSet.Parse.
@erdnaxeli — the original question is wanting to take an arbitrary string (as if entered on the command line) and parse it into "words" as the shell would do, producing an argv. For instance, the string foo bar"baz" -o some \file.name".txt" would be parsed into the words foo, barbaz, -o, and some file.name.txt. Then you need to decide whether or not you want to expand globs (you probably do).
Yes, you are right, my comment is off-topic.
1

Regex can use to detect each argument. There are two possible forms for an argument:

  1. a group of letters and a negative sign: [-a-zA-Z]+
  2. something sandwiched between two ": ".*?"

Information about regexp package: https://pkg.go.dev/regexp

Information about regexp syntax: https://pkg.go.dev/regexp/[email protected]

re := regexp.MustCompile(`([-a-zA-Z]+)|(".*?[^\\]")|("")`)
command := `unimportant -fb "quoted string"`

allArgs := re.FindAllString(command, -1)

//fmt.Printf("%+v\n", allArgs)

// to remove "
for _, arg := range allArgs {
    if arg[0] == '"' {
        arg = arg[1 : len(arg)-1]
    }
    fmt.Println(arg)
}

Output:

unimportant
-fb
quoted string

2 Comments

What about escaped quotes like in unimportant -fb "quoted string \"with\" escaped quotes"?
Regex changed in the answer: ([-a-zA-Z]+)|(".*?[^\\]")|("")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.