使用Golang执行带有双引号的命令。

huangapple go评论82阅读模式
英文:

Golang execute commands with double quotes

问题

我做了一个简单的程序,它接受用户输入并将其作为系统命令执行。

这段代码接受用户输入并将其存储在command变量中:

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("无法运行命令:", err)
}

现在,当我执行像ipconfig、arp -a、ping这样的命令时,一切都很顺利,并且输出会在执行时打印出来,但是当我尝试在命令中使用双引号时,它就会出错。

问题:
我尝试执行以下命令:echo hello world > file.txt,这个命令可以正常工作,但是一旦我将文件名放在引号中:echo hello world > "file.txt",我就会得到退出状态1,并且从标准错误中得到的错误信息是:文件名、目录名或卷标语法不正确。

我尝试过:

  • 搜索,甚至向chat-gpt询问,但我无法弄清楚为什么会出现这种情况。
  • 在执行命令之前将引号替换为:"或^",但都没有起作用。

我使用的是Windows 10。

完整代码以便更好地理解:

package main

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
)

type customOutput struct{}

func (c customOutput) Write(p []byte) (int, error) {
	fmt.Println("接收到输出:", 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("无法运行命令:", err)
    }
}
英文:

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:

  • searching, even asking chat-gpt but I can't figure out why this happens.
  • replacing the quotes before executing the command to: " or ^" but nothing works.

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)
    }
}

答案1

得分: 2

你需要执行以下操作:

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("无法运行命令:", err)
}

然后可能需要在命令中转义引号。

在Windows上,进程将整个命令行作为单个字符串接收并进行自己的解析。Command使用与使用CommandLineToArgvW的应用程序兼容的算法将Args组合和引用为命令行字符串。值得注意的例外是msiexec.exe和cmd.exe(以及所有批处理文件),它们具有不同的取消引用算法。在这些或类似情况下,您可以自己进行引用并在SysProcAttr.CmdLine中提供完整的命令行,将Args留空。

英文:

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.

huangapple
  • 本文由 发表于 2023年4月6日 23:56:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75951491.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定