douxiong5438
douxiong5438
2015-12-06 14:53
浏览 124
已采纳

将命令行字符串解析为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

I've checked the built-in flag package as well as other flag handling packages on Github but none of them seem to handle this particular case of parsing a raw string into tokens. Before trying to do it myself I'd rather look for a package as I'm sure there are a lot of special cases to handle.

Any suggestion?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • doushuo1080
    doushuo1080 2017-10-27 11:05
    已采纳

    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
    }
    
    点赞 评论
  • dongzipu7517
    dongzipu7517 2018-05-27 03:57

    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"}
    

    If you just have the string though, for some reason, and you'd like to mimic what the shell would do with it, then I recommend a package like https://github.com/kballard/go-shellquote

    点赞 评论
  • dongzhi4239
    dongzhi4239 2019-05-30 08:39

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

    点赞 评论

相关推荐