This page looks best with JavaScript enabled

Go在windows上调用本地进程传参时的一个天坑

 ·   ·  ☕ 2 min read  ·  ✍️ oser

go在windows上exec.Command调用本地进程在传参的时候有一个天坑,举个栗子来说正常来说一般代码会这么写

1
2
3
 cmdLine := "notepad.exe " + `"D:\Program Files\Notepad++\session.xml"`
 cmd := exec.Command("cmd.exe", "/c", cmdLine)
 err := cmd.Run()

我们期望在拉起notepad的时候是会正常解析参数并打开xml文件的,但是,你可以尝试运行一下这段代码,结果并不是我们想的这样!

notepad在打开的时候会报一个非法路径,这是怎么回事呢?打开processexp看一下传入的参数如下

1
notepad.exe  \"D:\Program Files\Notepad++\session.xml\"

看到在双引号中强制加入了转义符,一开始我以为这是string里强制加入的,想到这做法也太奇怪了,强制转string为byte[]后,一个一个对字符发现原字符串中根本就没有出现转义符,搜遍国内外只有提问的人,却没找到有效的解决办法。

想了一下,那这问题必然就出在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.

也就是说,针对cmd参数加的引号参数会有不同的逻辑,必须在SysProcAttr.CmdLine中写入原始参数了,但是Args留空,又会导致SysProcAttr值为nil,所以简单赋值也是不行的,那么正确的代码实现如下

1
2
3
4
 cmdLine := "notepad.exe " + `"D:\Program Files\Notepad++\session.xml"`
 cmd := exec.Command("cmd.exe")
 cmd.SysProcAttr = &syscall.SysProcAttr{CmdLine: "/c " + cmdLine}
 err := cmd.Run()

运行一下,果然notepad正确打开了文件

Share on

oser
WRITTEN BY
oser
愿我的狗子在天堂也能每天开心咧嘴笑