From 9146d1ced257b7726aaaaba00ea9d43fbd3c55f9 Mon Sep 17 00:00:00 2001 From: aiko Date: Thu, 9 Oct 2025 00:18:04 -0400 Subject: [PATCH 1/3] running commands via user shell --- internal/shell/shell.go | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/internal/shell/shell.go b/internal/shell/shell.go index 9149da9f79..e9848998a3 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) { @@ -40,9 +60,9 @@ func RunCommand(input string) (string, error) { 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 +97,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 +105,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) From 3f1b315b200c0078ff28ba86f93d5b7e1116013f Mon Sep 17 00:00:00 2001 From: aiko Date: Thu, 9 Oct 2025 01:06:11 -0400 Subject: [PATCH 2/3] removed shellquote stripping chars when not needed --- internal/action/command.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 { From 9db5ed0078fcf925b70122da6bbbcee9bbb76144 Mon Sep 17 00:00:00 2001 From: aiko Date: Thu, 9 Oct 2025 01:07:38 -0400 Subject: [PATCH 3/3] removed unneeded shellquote call from RunCommand --- internal/shell/shell.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/internal/shell/shell.go b/internal/shell/shell.go index e9848998a3..b1f535c04d 100644 --- a/internal/shell/shell.go +++ b/internal/shell/shell.go @@ -53,12 +53,8 @@ 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 len(args) == 0 { - return "", errors.New("No arguments") + if input == "" { + return "", errors.New("No command") } shell, flag := getShell()