@laurent 's answer is wonderful, but it doesn't work when command
includes utf-8 char.
It fail the third test:
func TestParseCommandLine(t *testing.T){
tests := []struct{
name string
input string
want []string
}{
{
"normal",
"hello world",
[]string{"hello", "world"},
},
{
"quote",
"hello \"world hello\"",
[]string{"hello", "world hello"},
},
{
"utf-8",
"hello 世界",
[]string{"hello", "世界"},
},
{
"space",
"hello\\ world",
[]string{"hello world"},
},
}
for _, tt := range tests{
t.Run(tt.name, func(t *testing.T) {
got, _ := parseCommandLine(tt.input)
if !reflect.DeepEqual(got, tt.want){
t.Errorf("expect %v, got %v", tt.want, got)
}
})
}
}
Based on his/her answer, i wrote this func that works good for utf-8, just by replacing for i := 0; i < len(command); i++ {c := command[i]
to for _, c := range command
Here's the my answer:
func parseCommandLine(command string) ([]string, error) {
var args []string
state := "start"
current := ""
quote := "\""
escapeNext := true
for _, c := range command {
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
}
flag
package's documentation): set := &flag.FlagSet{} v := set.Bool("v", false, "") format := set.String("format", "", "") i := set.String("i", "", "") set.Parse([]string{-v
,--format="some example"
,-i=test
}) for k, v := range set.Args() { log.Println(k, v) } log.Printf("v=%v format=%v i=%v", *v, *format, *i) – Bessbessarabiacmd -v --format "some example" -i test
? If so, you could just grab all of the arguments fromos.Args
. – Punchdrunkopt.SetUnknownMode("pass")
will leave things as you want them in theremaining
slice. – Vaccaro