Парсить командную строку в флаги и аргументы в Golang

Я ищу пакет, который будет принимать строку типа -v --format "some example" -i test и разберите его на фрагмент строк, обрабатывая кавычки, пробелы и т. д. правильно:

-v
--format
some example
-i
test

Я проверил встроенный flag пакет, а также другие пакеты обработки флагов на Github, но ни один из них, похоже, не обрабатывает этот конкретный случай разбора необработанной строки на токены. Прежде чем пытаться сделать это сам, я бы предпочел искать пакет, поскольку я уверен, что есть много особых случаев ручка.

любое предложение?

2 ответов


для информации, это функция, которую я в конечном итоге создал.

он разбивает команду на его аргументы. Например, cat -v "some file.txt" вернет ["cat", "-v", "some file.txt"].

Он также правильно обрабатывает экранированные символы, в частности пробелы. Так что cat -v some\ file.txt также будет правильно разбит на ["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
}

Если args были переданы вашей программе в командной строке, то оболочка должна обрабатывать это и os.Args будет заполнено правильно. Например, в вашем случае os.Args[1:] будет равна

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

Если у вас просто есть строка, по какой-то причине, и вы хотели бы имитировать то, что оболочка будет делать с ней, тогда я рекомендую пакет, такой как https://github.com/kballard/go-shellquote