parser.go

 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}