func Exec(str string) (*ExecResult, error) {
	var cmdstr string
	var args []string
	var l int
	spl := strings.Split(str, " ")
	l = len(spl)
	if l == 1 {
		cmdstr = spl[0]
	} else if l > 1 {
		cmdstr = spl[0]
		for i := 1; i < l; i++ {
			args = append(args, spl[i])
		}
	} else if l < 1 {
		return nil, fmt.Errorf("invalid Exec() string %s", str)
	}
	fqpcmd, err := exec.LookPath(cmdstr)
	if err != nil {
		logger.Debug("unable to find fully qualified path for executable %s: %v", cmdstr, err)
	}
	stdoutBuffer := bytes.Buffer{}
	stderrBuffer := bytes.Buffer{}
	e := []string{fqpcmd}
	for _, arg := range args {
		e = append(e, arg)
	}
	cmd := exec.Command(e[0], e[1:]...)
	cmd.Stdout = &stdoutBuffer
	cmd.Stderr = &stderrBuffer
	result := &ExecResult{}
	err = cmd.Run()
	if err != nil {
		if eerr, ok := err.(*exec.ExitError); ok {
			result.stderr = stderrBuffer.String()
			result.stdout = stdoutBuffer.String()
			result.exitCode = eerr.ExitCode()
			result.execErr = *eerr
			return result, nil
		}
		return nil, fmt.Errorf("major error running command [%s]: %v", str, err)
	}
	result.stderr = stderrBuffer.String()
	result.stdout = stdoutBuffer.String()
	result.exitCode = 0
	return result, nil
}
Exec will take an arbitrary executable string
and hang until the command exits
package sampleapp
import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os/exec"
	"path/filepath"
	"strings"
	"github.com/kris-nova/logger"
)
type Script struct {
	commands []string
}
func NewScriptFromPath(path string) (*Script, error) {
	path, err := filepath.Abs(path)
	if err != nil {
		return nil, fmt.Errorf("unable to calculate fully qualified path for path: %s: %v", path, err)
	}
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("unable to read from path %s: %v", path, err)
	}
	content := string(bytes)
	return NewScriptFromString(content), nil
}
const (
	IgnoreSpacesBash string = "    "
	IgnoreTabs string = "\t"
)
func NewScriptFromString(str string) *Script {
	script := &Script{}
	removeRuleF := func(str string, rs []string) string {
		for _, r := range rs {
			str = strings.Replace(str, r, "", -1)
		}
		return str
	}
	str = strings.Replace(str, "\\\n", "", -1)
	str = removeRuleF(str, []string{IgnoreSpacesBash, IgnoreTabs})
	spl := strings.Split(str, "\n")
	for _, line := range spl {
		script.commands = append(script.commands, line)
	}
	return script
}
func (s *Script) Interpret() error {
	for i, cmdStr := range s.commands {
		if cmdStr == "\n" || cmdStr == "" || strings.HasPrefix(cmdStr, "#") || strings.HasPrefix(cmdStr, "//") {
			continue
		}
		logger.Info("Executing: [%s]", cmdStr)
		result, err := Exec(cmdStr)
		if err != nil {
			return fmt.Errorf("error executing  running command [%s] on line [%d]\n%v\n", cmdStr, i+1, err)
		} else if result.exitCode != 0 {
			return fmt.Errorf("non zero exit code running command [%s] on line [%d]\n%s\n%s\n", cmdStr, i+1, result.Stdout(), result.Stderr())
		}
		logger.Debug(result.Stdout())
	}
	return nil
}
type ExecResult struct {
	stderr   string
	stdout   string
	exitCode int
	execErr  exec.ExitError
}
func (e *ExecResult) Stdout() string {
	return e.stdout
}
func (e *ExecResult) Stderr() string {
	return e.stderr
}
func (e *ExecResult) ExitCode() int {
	if e == nil {
		return 0
	}
	return e.exitCode
}
func (e *ExecResult) ExecError() exec.ExitError {
	return e.execErr
}