Golang中如何使用exec.Command传递参数

Golang中如何使用exec.Command传递参数 我正在使用 golang 的 “os/exec” 包来调用带参数的 Windows 程序。

如果使用以下方式调用程序:

app.exe /param1:"0 1 2"

程序返回正常

如果使用以下方式调用程序:

app.exe "/param1:0 1 2"

程序返回错误

我的问题是无法使用 exec.Command 正确调用该程序。

我编写了一个示例 C# 程序:

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Environment.CommandLine);
            if (Environment.CommandLine.EndsWith("/param1:\"0 1 2\""))
            {
                Console.WriteLine("argument is valid");
            }
            else
            {
                Console.WriteLine("argument is invalid");
            }
            return;
        }
    }
}

这是我的 Go 代码:

package main

import (
	"fmt"
	"os/exec"
)

func main() {
	arg1 := `/param1:"0 1 2"`
	fmt.Println(arg1)
	data, err := exec.Command("./ConsoleApp1.exe", arg1).Output()
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data))

	arg1 = `"/param1:0 1 2"`
	fmt.Println(arg1)
	data, err = exec.Command("./ConsoleApp1.exe", arg1).Output()
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data))

	arg1 = `/param1:0 1 2`
	fmt.Println(arg1)
	data, err = exec.Command("./ConsoleApp1.exe", arg1).Output()
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data))
	return
}

输出结果是:

/param1:"0 1 2"
./ConsoleApp1.exe "/param1:\"0 1 2\""
argument is invalid

"/param1:0 1 2"
./ConsoleApp1.exe "\"/param1:0 1 2\""
argument is invalid

/param1:0 1 2
./ConsoleApp1.exe "/param1:0 1 2"
argument is invalid

有人能帮我吗?谢谢。


更多关于Golang中如何使用exec.Command传递参数的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

看来我不得不编写一个批处理文件,然后通过 os/exec 来调用这个批处理文件。

更多关于Golang中如何使用exec.Command传递参数的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这只是一个示例C#程序。

我想调用另一个由他人编写的程序(从互联网下载)。

我明白了。那个程序使用的是 Environment.CommandLine 而不是 Environment.GetCommandLineArgs 来读取参数吗?

在C#程序中,你可以改用Environment.GetCommandLineArgs()方法,这样应该就能获取到不带额外引号的参数了。

该程序是用C++编写的。

我认为该程序使用了类似Environment.CommandLine的功能。

我的测试(Windows命令行):

// 正常
app.exe /param1:"0 1 2"
// 错误
app.exe "/param1:0 1 2"

在 Windows 系统中,exec.Command 的参数传递方式与命令行直接调用有所不同。问题在于 Go 的 exec.Command 会自动对参数进行转义处理,而 Windows 命令行解析器对引号的处理方式比较特殊。

以下是正确的解决方案:

package main

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

func main() {
    // 方法1:使用 syscall 直接设置命令行字符串
    cmd := exec.Command("ConsoleApp1.exe")
    cmd.SysProcAttr = &syscall.SysProcAttr{
        CmdLine: `ConsoleApp1.exe /param1:"0 1 2"`,
    }
    
    data, err := cmd.Output()
    if err != nil {
        panic(err)
    }
    fmt.Println(string(data))
    
    // 方法2:使用正确的参数拆分方式
    cmd2 := exec.Command("ConsoleApp1.exe", `/param1:0 1 2`)
    data2, err := cmd2.Output()
    if err != nil {
        panic(err)
    }
    fmt.Println(string(data2))
}

或者更简洁的版本:

package main

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

func main() {
    cmd := exec.Command("cmd.exe", "/C", `ConsoleApp1.exe /param1:"0 1 2"`)
    
    data, err := cmd.Output()
    if err != nil {
        panic(err)
    }
    fmt.Println(string(data))
}

关键点说明:

  1. 使用 syscall.SysProcAttr.CmdLine:这种方法直接设置完整的命令行字符串,绕过了 Go 的参数解析,完全按照 Windows 的命令行格式传递。

  2. 通过 cmd.exe 调用:使用 cmd.exe /C 来执行完整的命令行,这样参数会按照 Windows 命令行的标准方式解析。

  3. 避免不必要的引号:在直接传递参数时,不要额外添加引号,让 Go 和 Windows 自行处理参数中的空格。

你的 C# 程序检查的是 Environment.CommandLine,这是完整的命令行字符串,而不是解析后的 args 数组。因此使用 syscall.SysProcAttr.CmdLine 是最直接的方法,可以确保命令行字符串完全符合预期格式。

回到顶部