Skip to content

Commit

Permalink
👔 up: sysutil - ShellExec support handle use cmd,pwsh shell on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Oct 23, 2024
1 parent c97c8d0 commit c1f379f
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
10 changes: 10 additions & 0 deletions internal/checkfn/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,13 @@ func Contains(data, elem any) (valid, found bool) {
}
return true, false
}

// StringsContains check string slice contains string
func StringsContains(ss []string, s string) bool {
for _, v := range ss {
if v == s {
return true
}
}
return false
}
31 changes: 26 additions & 5 deletions sysutil/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os/exec"

"github.com/gookit/goutil/cliutil/cmdline"
"github.com/gookit/goutil/internal/checkfn"
"github.com/gookit/goutil/sysutil/cmdr"
)

Expand All @@ -13,17 +14,19 @@ func NewCmd(bin string, args ...string) *cmdr.Cmd {
return cmdr.NewCmd(bin, args...)
}

// FlushExec instance
// FlushExec command, will flush output to stdout,stderr
func FlushExec(bin string, args ...string) error {
return cmdr.NewCmd(bin, args...).FlushRun()
}

// QuickExec quick exec an simple command line
// QuickExec quick exec a simple command line
func QuickExec(cmdLine string, workDir ...string) (string, error) {
return ExecLine(cmdLine, workDir...)
}

// ExecLine quick exec an command line string
// ExecLine quick exec a command line string.
//
// NOTE: not support | or ; in cmdLine
func ExecLine(cmdLine string, workDir ...string) (string, error) {
p := cmdline.NewParser(cmdLine)

Expand Down Expand Up @@ -53,16 +56,34 @@ func ExecCmd(binName string, args []string, workDir ...string) (string, error) {
return string(bs), err
}

// ShellExec exec command by shell cmdLine. eg: "ls -al"
// ShellExec exec command by shell cmdLine.
//
// shells e.g. "/bin/sh", "bash", "cmd", "cmd.exe", "powershell", "powershell.exe", "pwsh", "pwsh.exe"
//
// eg: ShellExec("ls -al")
func ShellExec(cmdLine string, shells ...string) (string, error) {
// shell := "/bin/sh"
shell := "sh"
if len(shells) > 0 {
shell = shells[0]
}

// "-c" for bash,sh,zsh shell
mark := "-c"

// special for Windows shell
if IsWindows() {
// use cmd.exe, mark is "/c"
if checkfn.StringsContains([]string{"cmd", "cmd.exe"}, shell) {
mark = "/c"
} else if checkfn.StringsContains([]string{"powershell", "powershell.exe", "pwsh", "pwsh.exe"}, shell) {
// "-Command" for powershell
mark = "-Command"
}
}

var out bytes.Buffer
cmd := exec.Command(shell, "-c", cmdLine)
cmd := exec.Command(shell, mark, cmdLine)
cmd.Stdout = &out

if err := cmd.Run(); err != nil {
Expand Down
24 changes: 24 additions & 0 deletions sysutil/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ import (
"github.com/gookit/goutil/testutil/assert"
)

func TestNewCmd(t *testing.T) {
c := sysutil.NewCmd("echo", "OK")
assert.Eq(t, "OK", c.Args[1])
}

func TestFlushExec(t *testing.T) {
err := sysutil.FlushExec("echo", "OK")
assert.NoErr(t, err)
}

func TestExecCmd(t *testing.T) {
ret, err := sysutil.ExecCmd("echo", []string{"OK"})
assert.NoErr(t, err)
Expand All @@ -32,4 +42,18 @@ func TestShellExec(t *testing.T) {
ret, err = sysutil.ShellExec("echo OK", "bash")
assert.NoErr(t, err)
assert.Eq(t, "OK", strings.TrimSpace(ret))

if sysutil.IsWindows() {
t.Run("cmd", func(t *testing.T) {
ret, err := sysutil.ShellExec("echo OK", "cmd")
assert.NoErr(t, err)
assert.Eq(t, "OK", strings.TrimSpace(ret))
})

t.Run("powershell", func(t *testing.T) {
ret, err := sysutil.ShellExec("echo OK", "powershell")
assert.NoErr(t, err)
assert.Eq(t, "OK", strings.TrimSpace(ret))
})
}
}

0 comments on commit c1f379f

Please sign in to comment.