diff --git a/internal/action/command.go b/internal/action/command.go index 7cb5e523bc..71e542da4f 100644 --- a/internal/action/command.go +++ b/internal/action/command.go @@ -873,7 +873,8 @@ func (h *BufPane) UnbindCmd(args []string) { // RunCmd runs a shell command in the background func (h *BufPane) RunCmd(args []string) { - runf, err := shell.RunBackgroundShell(shellquote.Join(args...)) + // using strings.Join instead of shellquote to prevent escaping certain chars + runf, err := shell.RunBackgroundShell(strings.Join(args, " ")) if err != nil { InfoBar.Error(err) } else { diff --git a/internal/shell/shell.go b/internal/shell/shell.go index 9149da9f79..b1f535c04d 100644 --- a/internal/shell/shell.go +++ b/internal/shell/shell.go @@ -8,12 +8,32 @@ import ( "os" "os/exec" "os/signal" + "runtime" shellquote "github.com/kballard/go-shellquote" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" ) +// getShell returns user's default shell and the arg needed to run a command string +func getShell() (shell string, arg string) { + if runtime.GOOS == "windows" { + // use powershell if available, otherwise cmd + if pwsh := os.Getenv("ComSpec"); pwsh != "" { + return pwsh, "/C" + } + return "cmd", "/C" + } + + // unix-like + shell = os.Getenv("SHELL") + if shell == "" { + shell = "/bin/sh" + } + return shell, "-c" + // TODO check if the user's shell actually uses this flag +} + // ExecCommand executes a command using exec // It returns any output/errors func ExecCommand(name string, arg ...string) (string, error) { @@ -33,16 +53,12 @@ func ExecCommand(name string, arg ...string) (string, error) { // RunCommand executes a shell command and returns the output/error func RunCommand(input string) (string, error) { - args, err := shellquote.Split(input) - if err != nil { - return "", err + if input == "" { + return "", errors.New("No command") } - if len(args) == 0 { - return "", errors.New("No arguments") - } - inputCmd := args[0] - return ExecCommand(inputCmd, args[1:]...) + shell, flag := getShell() + return ExecCommand(shell, flag, input) } // RunBackgroundShell runs a shell command in the background @@ -77,7 +93,6 @@ func RunInteractiveShell(input string, wait bool, getOutput bool) (string, error if len(args) == 0 { return "", errors.New("No arguments") } - inputCmd := args[0] // Shut down the screen because we're going to interact directly with the shell screenb := screen.TempFini() @@ -86,7 +101,8 @@ func RunInteractiveShell(input string, wait bool, getOutput bool) (string, error // Set up everything for the command outputBytes := &bytes.Buffer{} - cmd := exec.Command(inputCmd, args...) + shell, flag := getShell() + cmd := exec.Command(shell, flag, input) cmd.Stdin = os.Stdin if getOutput { cmd.Stdout = io.MultiWriter(os.Stdout, outputBytes)