I made a simple program which takes user input and then executes it as a system command.
This takes user input and stores it in command variable:
fmt.Print("> ")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
command := scanner.Text()
Then I execute it and print out Stdout aswell as Stderr:
cmd := exec.Command("cmd", "/c", command)
cmd.Stdout = customOutput{}
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Println("could not run command: ", err)
}
Now when I execute command like: ipconfig, arp -a, ping, it all works great and the output is getting printed out as it executes, but when I try to use double quotes in the command it just breaks.
The problem:
I tried doing: echo hello world > file.txt
and this works fine but as soon as I put the filename in quotes: echo hello world > "file.txt"
I'm getting exit status 1 and from Stderr I'm getting: The filename, directory name, or volume label syntax is incorrect.
I tried:
I'm using windows 10 btw.
Full code for better understanding:
package main
import (
"bufio"
"fmt"
"os"
"os/exec"
)
type customOutput struct{}
func (c customOutput) Write(p []byte) (int, error) {
fmt.Println("received output: ", string(p))
return len(p), nil
}
func main() {
fmt.Print("> ")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
command := scanner.Text()
cmd := exec.Command("cmd", "/c", command)
cmd.Stdout = customOutput{}
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Println("could not run command: ", err)
}
}
You need to do
cmd := exec.Command("cmd.exe")
cmd.SysProcAttr = &syscall.SysProcAttr{CmdLine: fmt.Sprintf(`/c "%s"`, command)}
cmd.Stdout = customOutput{}
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Println("could not run command: ", err)
}
and then probably escape the quotes in command.
https://pkg.go.dev/os/exec#Command
On Windows, processes receive the whole command line as a single string and do their own parsing. Command combines and quotes Args into a command line string with an algorithm compatible with applications using CommandLineToArgvW (which is the most common way). *Notable exceptions are msiexec.exe and cmd.exe (and thus, all batch files), which have a different unquoting algorithm. In these or other similar cases, you can do the quoting yourself and provide the full command line in SysProcAttr.CmdLine, leaving Args empty.