Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion internal/action/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
36 changes: 26 additions & 10 deletions internal/shell/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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)
Expand Down