Skip to content

Instantly share code, notes, and snippets.

@jmervine
Last active July 1, 2021 03:38
Show Gist options
  • Save jmervine/d88c75329f98e09f5c87 to your computer and use it in GitHub Desktop.
Save jmervine/d88c75329f98e09f5c87 to your computer and use it in GitHub Desktop.
Golang: Safely Split a string containing a shell command.
// safeSplit handles quoting well for commands for use with github.com/jmervine/exec/v2
//
// Examples:
// > safeSplit("/bin/bash bash -l -c 'echo \"foo bar bah bin\"'")
// => []string{"/bin/bash", "-l", "-c", "echo \"foo bar bah bin\""}
// > safeSplit("docker run --rm -it some/image bash -c \"npm test\"")
// => []string{"docker", "run", "--rm", "-it", "some/image", "bash", "-c", "npm test"}
//----
// package main
// import "github.com/jmervine/exec/v2"
// import "fmt"
// action := safeSplit("docker run --rm -it some/image bash -c \"npm test\"")
// out, err := exec.Exec(action[0], action[1:]...)
// if err != nil { panic(err) }
// fmt.Println(out)
//----
import "strings"
func safeSplit(s string) []string {
split := strings.Split(s, " ")
var result []string
var inquote string
var block string
for _, i := range split {
if inquote == "" {
if strings.HasPrefix(i, "'") || strings.HasPrefix(i, "\"") {
inquote = string(i[0])
block = strings.TrimPrefix(i, inquote) + " "
} else {
result = append(result, i)
}
} else {
if !strings.HasSuffix(i, inquote) {
block += i + " "
} else {
block += strings.TrimSuffix(i, inquote)
inquote = ""
result = append(result, block)
block = ""
}
}
}
return result
}
@rbucker
Copy link

rbucker commented Feb 20, 2017

this code does not work if the quoted string does not have spaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment