1package shell
2
3import (
4 "fmt"
5 "strings"
6
7 "mvdan.cc/sh/v3/syntax"
8)
9
10// ParseCommand parses a command string into the command name and arguments.
11// It handles quoted arguments and other shell syntax.
12func ParseCommand(command string) (string, []string, error) {
13 parsed, err := syntax.NewParser().Parse(strings.NewReader(command), "")
14 if err != nil {
15 return "", nil, fmt.Errorf("failed to parse command: %w", err)
16 }
17
18 var cmdName string
19 var cmdArgs []string
20
21 if len(parsed.Stmts) > 0 && parsed.Stmts[0].Cmd != nil {
22 if callExpr, ok := parsed.Stmts[0].Cmd.(*syntax.CallExpr); ok && len(callExpr.Args) > 0 {
23 for i, arg := range callExpr.Args {
24 var argStr string
25 for _, part := range arg.Parts {
26 if lit, ok := part.(*syntax.Lit); ok {
27 argStr += lit.Value
28 }
29 }
30 if i == 0 {
31 cmdName = argStr
32 } else {
33 cmdArgs = append(cmdArgs, argStr)
34 }
35 }
36 }
37 }
38
39 // Fallback if parsing produced no command name (e.g. empty string or comment only, though unlikely with valid input)
40 if cmdName == "" {
41 return command, nil, nil
42 }
43
44 return cmdName, cmdArgs, nil
45}