将命令行字符串解析为Golang中的标志和参数

/ go / 没有评论 / 1551浏览

将命令行字符串解析为Golang中的标志和参数

I'm looking for a package that would take a string such as -v --format "some example" -i test and parse it into a slice of strings, handling quotes, spaces, etc. properly:

-v
--format
some example
-i
test

For information, this is the function I've ended up creating.

It splits a command into its arguments. For example, cat -v "some file.txt", will return ["cat", "-v", "some file.txt"].

It also correctly handles escaped characters, spaces in particular. So cat -v some\ file.txt will also correctly be split into ["cat", "-v", "some file.txt"]

func parseCommandLine(command string) ([]string, error) {
    var args []string
    state := "start"
    current := ""
    quote := """
    escapeNext := true
    for i := 0; i < len(command); i++ {
        c := command[i]
 
        if state == "quotes" {
            if string(c) != quote {
                current += string(c)
            } else {
                args = append(args, current)
                current = ""
                state = "start"
            }
            continue
        }
 
        if (escapeNext) {
            current += string(c)
            escapeNext = false
            continue
        }
 
        if (c == '\\') {
            escapeNext = true
            continue
        }
 
        if c == '"' || c == '\'' {
            state = "quotes"
            quote = string(c)
            continue
        }
 
        if state == "arg" {
            if c == ' ' || c == '\t' {
                args = append(args, current)
                current = ""
                state = "start"
            } else {
                current += string(c)
            }
            continue
        }
 
        if c != ' ' && c != '\t' {
            state = "arg"
            current += string(c)
        }
    }
 
    if state == "quotes" {
        return []string{}, errors.New(fmt.Sprintf("Unclosed quote in command line: %s", command))
    }
 
    if current != "" {
        args = append(args, current)
    }
 
    return args, nil
}

If the args were passed to your program on the command line then the shell should handle this and os.Args will be populated correctly. For example, in your case os.Args[1:] will equal

[]string{"-v", "--format", "some example", "-i", "test"}

hedzr/cmdr might be good. it's a getopt-like command-line parser, light weight, fluent api or classical style.