很简单的调用:
cmd := exec.Command( "TeraCopy.exe", fmt.Sprintf(`*"%s" "%s"`, copyPaths, targetDir) ) err := cmd.Start()
报错:
--------------------------- TeraCopy - Error --------------------------- File not found: \e:\**\tc.tmp \E:\**\b\ --------------------------- 确定 ---------------------------
??? 啥玩意 ???
本着出了问题先找自身原因的混帐话优良传统,控制台与 TeraCopy 软件试了各种参数,都正常……
感觉是转义出了问题,谷歌了半天,除了复制粘贴就没别的了。
米田共里淘金终于发现了一片文章:Go 在 windows 上调用本地进程传参时的一个天坑
MD ,最终 tm 还是 go 的问题,一直不敢往那想,属实被喷怕了。 摘抄一下:
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 ,所以简单赋值也是不行的
改了一下代码:
cmdLine := fmt.Sprintf(`copy *"%s" "%s"`, copyPaths, targetDir) cmd := exec.Command("TeraCopy.exe") cmd.SysProcAttr = &syscall.SysProcAttr{CmdLine: "/c " + cmdLine} err := cmd.Start()
解决。
学习 go 一段时间,觉得它的开发者很矛盾,比如三元运算符,很多人都想要它,但官方却以语法统一、可能会导致阅读困难之类的理由推脱。 但
return r ? true : false
不比你 if 要整洁易读? 对多字节的处理也很费劲,我到现在不知道怎样查找某个中文的位置,IndexRune 报错,也没谷歌到答案
fmt.Println(strings.IndexRune("学习", "习")) Error ./prog.go:9:42: cannot use "习" (untyped string constant) as rune value in argument to strings.IndexRune
是不是有人要说,爱用用,不用滚呢?
1 haochen2 2022-04-08 17:39:26 +08:00 ![]() strings.IndexRune 建议好好看看函数签名,第二个参数是 rune 类型,你给了个字符串 |
![]() | 2 darrh00 2022-04-08 17:45:38 +08:00 strings.IndexRune("学习", '习') |
![]() | 3 ikaros 2022-04-08 17:46:42 +08:00 啊? 第一个问题报错 file not found 应该很好一步步排查吧; 第二个错误也说了 cannot use "习" (untyped string constant) as rune value in argument to strings.IndexRune ,而且这个是编译期的问题,编辑器就能提示出来的吧;顺带我也觉得 go 有点烂,转 rust 吧 |
4 haochen2 2022-04-08 17:47:13 +08:00 go 标准库实现的质量非常高,希望能抱着学习的心态去探索她它 |
![]() | 5 keepeye 2022-04-08 17:52:29 +08:00 哈哈 你之前用的啥? java 吗? |
6 fishCatcher 2022-04-08 17:55:56 +08:00 via iPhone ![]() 来跟我一个字一个字读:cannot use untyped string constant as rune value in argument |
![]() | 7 Mohanson 2022-04-08 17:57:41 +08:00 ![]() exec.Command 每一个 args 都要做一个参数传的, 正确写法是 `exec.Command("TeraCopy.exe", copyPaths, targetDir)` 另外真的很烦你这种人... |
![]() | 8 v2kt 2022-04-08 17:58:39 +08:00 cannot use untyped string constant as rune value in argument |
![]() | 9 mogita 2022-04-08 17:59:31 +08:00 对,会有人说的。 |
![]() | 10 Trim21 2022-04-08 18:04:30 +08:00 via Android exec.Command 的 args 是直接传进去的,不需要用 fmt 再拼接一下,这地方不是 shell 还会解析你的命令行。(这个问题在其他语言其实也有类似的) string 和 rune 不是一个东西。 |
![]() | 11 sqfphoenix 2022-04-08 18:04:42 +08:00 cmd := exec.Command("notepad.exe", filepath.Join("D:/", "metrics.txt")) 使用 filepath 很难吗 使用 cmd.String()输出看看自己的命令很难吗 看一下 strings 的源码很难吗 |
![]() | 12 lance6716 2022-04-08 18:14:36 +08:00 via Android 无力吐槽,再说两个 return r ? true : false 跟 return r 有什么区别? 调用 exec.Command 之前不会看一眼他的函数注释? |
![]() | 13 ScepterZ 2022-04-08 18:16:46 +08:00 实习那年遇到过这个问题,后来发现是每个 args 要单独传,不能自己拼起来 最后那个,分不清字符和字符串实在不是语言的问题 |
14 CRVV 2022-04-08 18:18:54 +08:00 ![]() 这个传参数的问题实际上是 Windows 的问题,我大概解释一下 首先,大家通常理解的参数,是一个数组。 C 语言里面会写 int main( int argc, char* argv[] ),Java 会写 public static void main(String[] args),参数都是数组。 所以 Go 的 exec.Command 是 func Command(name string, arg ...string) *Cmd 。arg 也是数组,写 Command("echo", "a", "b", "c") 就是传了 3 个参数给 echo 。 但是,Windows 里面的参数是一个字符串,也就是 Go 的文档里面说的 “On Windows, processes receive the whole command line as a single string” Windows 里面的程序在接收到这个大字符串以后,再自己把它拆成数组,得到大家通常理解的一串参数。 问题在于,Windows 不同的程序有不同的方法来拆这个字符串,所以拆出来的数组也不一样。 这里 Go 的行为是说,如果你在 Command 里传了一个数组的参数,那么 Go 就按照 Windows 通常的拆法把这些参数拼起来,但是 Windows 上的 cmd.exe 和 msiexec.exe 的拆法并不是那个通常的拆法,所以会出问题。如果你要调用的程序是 cmd.exe ,那么 Go 拼字符串的算法就是错的,请自己把字符串拼好了放到 SysProcAttr 里面。 但是楼主调用的程序不是 cmd.exe ,也就是说楼主遇到的问题根本不是这个问题。 我能看出来的问题,首先是一开始楼主少写了一个 copy ,然后是把两个参数拼到了一个参数里面,那当然不能用了。 这个问题和 Go 和 Windows 都没有关系,纯粹是楼主自己的问题。 把这个事讲完,把两个参数拼到一个参数里面的意思是 cat a b 是说把 a 和 b 两个文件的内容打出来 cat "a b" 是说有一个文件的文件名是 a 空格 b ,把这一个文件的内容打出来,如果你想要的是前一种,这样写就会报错说找不到文件 |
![]() | 15 cassyfar 2022-04-08 18:21:13 +08:00 这种水平也来杠? |
![]() | 16 ChrisFreeMan 2022-04-08 18:23:55 +08:00 via iPhone go 的话题真活跃啊,问个 swift 的问题半天没人理 |
17 thevita 2022-04-08 18:29:41 +08:00 ![]() 比较适合些 PHP ---- 没有看不起 PHP 的意思,PHP 是最好的语言 |
![]() | 18 ysc3839 2022-04-08 18:42:43 +08:00 @CRVV 补充一下,类 Unix 系统传递的参数就是字符串数组,调用方怎么传递的,接收方可以原样接收到,不需要考虑引号、转义之类的问题。 |
19 PlG5sBkXD1ziLeGB 2022-04-08 18:47:24 +08:00 via iPhone 排错能力不太行呀兄弟 |
20 0o0O0o0O0o 2022-04-08 18:55:35 +08:00 via iPhone 我也至今没搞懂 rune ,所以会避免用…不过我明白这是因为自己菜,菜是因为自己懒不去读文档 我偶尔用 go 写一些 windows 的小工具,遇到过一些真正的坑,不过我对平台相关或是 cgo 相关的坑都比较宽容… |
21 ec0 2022-04-08 18:57:18 +08:00 fmt.Println(strings.IndexRune("学习", '习')) 为什么返回的是 3 ,我以为是 1 |
![]() | 22 KaynW 2022-04-08 18:59:48 +08:00 无力吐槽... |
![]() | 24 Tink PRO 真的无力吐槽 |
25 Jarvis666 2022-04-08 19:22:26 +08:00 想黑 win ,又想黑 go ,又质疑人家跨平台开发的能力,啧啧 |
26 listenerri 2022-04-08 19:43:36 +08:00 via Android ![]() “属实被喷怕了” 哈哈,建议 OP 慎重开喷,毕竟己不所欲勿施于人 |
27 deplivesb 2022-04-08 19:51:05 +08:00 又菜又爱吹 |
![]() | 28 skiy 2022-04-08 20:56:45 +08:00 @0o0O0o0O0o rune 是 int32 的别名,这个有什么难理解的?换个名称也一样的使用方式。 rune is an alias for int32 and is equivalent to int32 in all ways. https://github.com/golang/go/blob/5a90270d7f5b384de31399133c7336d007fbd93d/src/builtin/builtin.go#L92 |
29 0o0O0o0O0o 2022-04-08 21:28:26 +08:00 via iPhone @skiy 是的,不难理解,猜测也是类似于别的语言里统计 UTF-8 字符数的方式,如我在#20 的自我批评,就是懒... |
![]() | 30 Vegetable 2022-04-08 21:37:07 +08:00 ![]() 学而不思则罔,思而不学则殆。 我经常想发这句话,但是实际很少发。我觉得你很需要这句话。 |
![]() | 31 hallDrawnel 2022-04-08 21:51:53 +08:00 第一个问题,把参数拆开成数组,交给基础库去完成拼接这才是跨平台的做法,你可以在 docker 、k8s 和各种 IDE 中发现都是这样输入的。 第二点是纯粹连编译错误都不看。 你要是喷在点上那肯定是大家跟着你一起喷,但这明显是你菜啊。 |
![]() | 32 BeatifulSoap 2022-04-08 22:02:58 +08:00 via Android 其他不发表意见,但关于三元运算符我坚决站在 Go 这边 莫非定律了解下。只要语言给你用三元运算符,那绝对有程序员会拿它写出正常人没法轻松理解的代码。 比如每当看见 php 项目代码里有人把三元运算符玩出花的时候,我心里都是一万句草泥马 |
![]() | 33 zeronofreya OP ![]() @BeautifulSoap 那 goto 有何见解? |
![]() | 34 BeautifulSoap 2022-04-08 22:42:16 +08:00 @zeronofreya ?那还用问?当然是讨厌+反对 goto 咯,还有别的可能性?(当然 Go 一些功能你不用 goto 没法实现,有时候不得不捏着鼻子用) 所以,我一碗水端平了,你现在应该对于我坚决反对三元运算符没意见了吧? |
![]() | 35 skiy 2022-04-08 22:48:10 +08:00 你这知识面有点窄啊。。。 goto 是部分语言的一个特征。 C 语言的: https://www.runoob.com/cprogramming/c-goto-statement.html C++ 的: https://www.runoob.com/cplusplus/cpp-goto-statement.html C# 的: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/statements/jump-statements#the-goto-statement JAVA 虽然没有实现,但是保留了这个关键字。 |
![]() | 36 BeautifulSoap 2022-04-08 22:57:07 +08:00 @zeronofreya 对了,有的东西你真要比烂的话我觉得三元运算符 100%是要比 goto 更烂的 比如 php 同时支持 goto 和三元运算符,但我 review 和参与的所有 php 项目没一个人在 php 中用过 goto ,而相应的在 php 中瞎几把乱用三元运算符的一大堆 比起 goto ,三元运算符是一个很容易让写代码的人产生迷之自信,让人有一种我写出的“简洁”代码很酷的错觉 |
![]() | 37 liuzy1999 2022-04-08 23:00:57 +08:00 建议楼主加强英语能力与耐心,你会发现这些问题会改善很多的。 |
![]() | 38 surbomfla 2022-04-08 23:13:08 +08:00 via Android 无论是百度还是必应 搜索 strings.IndexRune 都有正确的用法示例,op 是怎么找到 `[]rune(str)` 这种用法的? |
![]() | 39 Tink PRO 你这个排错和搜索能力还需要提高 |
![]() | 40 singerll 2022-04-09 06:04:36 +08:00 via Android 不是针对 go ,三元运算符你说易读我真的不认同。 还有第一个问题,本人非专业开发运维人员,偶尔写点小脚本,我用 python 的 subprocess 模块也有这个问题,第一次用也是调了好久,说白了就是懒得扒拉官方文档,随便搜个教程开始写,最后出问题排除就是比较麻烦。。。 |
![]() | 41 xuanbg 2022-04-09 06:32:42 +08:00 @BeautifulSoap 连 Java 这种古板的语言都支持三元呢。。。 |
42 holulu 2022-04-09 06:52:04 +08:00 你摘的英文文章说得挺详细的。 |
43 yulon 2022-04-09 06:58:53 +08:00 为啥要用格式化组合参数啊,那么喜欢用格式化来写 C 吧。 Go 天生支持 Rune ,Windows 下还自动给你转码 Unicode ,居然说多语言不好处理,那来试试 C++ 吧。 怎么三元又能出来鞭尸一顿,那来写 C/C++ 啊,C 系的语法全都有吧。 什么爱用用咬不咬人,C++ 用好了绝对比用 Go 要爽。 所以快来写 C++ 啊!所以快来写 C++ 啊!所以快来写 C++ 啊! 你为什么还不来万能的 C++ 呢? |
![]() | 44 zjyl1994 2022-04-09 09:44:41 +08:00 via iPhone 天,大佬你学学英文吧,实在不行装个词典软件,编译器说的很明白了。这都不想弄,要不试试中文编程? |
45 tomolo 2022-04-09 09:51:12 +08:00 所以程序员还是需要学一点英语的 |
46 whileFalse 2022-04-09 09:55:21 +08:00 via iPhone 反正是有那种在三元里面套三元的傻*,比如我。 怎么说呢,我是运维但写了二十年代码,看别的运维的代码都是平趟,别人看我代码那就祝你好运吧,要是哪天不高兴写了个复杂的表达式就够你研究一会的,但对于我来说看懂类似的表达式跟看明白注释用时没啥区别。 所以,go 不让你用这种 c 遗留下来的语法是为你好啊孩子,我们这种老油条真的无所谓的。 |
47 carlclone 2022-04-09 10:12:41 +08:00 不如先找找自己水平问题再甩锅? |
![]() | 48 adoal 2022-04-09 10:13:26 +08:00 via iPhone 连三元运算符都能吵起来,那 if expression 你们是不是要当魔鬼了 |
49 fauieh32fihe 2022-04-09 10:41:45 +08:00 这种货色。。。哈哈 |
![]() | 51 yin1999 2022-04-09 12:45:42 +08:00 我真的是无语了,错误提示真有那么难看懂吗,strings.IndexRune 这个函数的第一个参数用的字符串,第二个参数用 rune ,要调用也应该是些 strings.IndexRune("学习", '习') 这么写,也就是 2 楼给出的答案,咋还能写成 strings.IndexRune([]rune("学习"), xxxx) 这样的呢(看你回复里面给出的错误提示都知道你的第一个参数填的啥了,这还不够明白吗) |
52 mengzhuo 2022-04-09 13:48:32 +08:00 额,感觉还是没仔细看错误提示…… 这样都能喷,来看看 Rust ,保证你一下午都编译不出来:) |
![]() | 53 rekulas 2022-04-09 14:17:23 +08:00 TeraCopy - Error 错误已经很明显了,被调用程序报的错,这都能怪到 go 的头上,你自己都乱喷就别怪别人喷你了 首先确保你参数正确,尽量用 git bash 调试好正确参数,然后复制到代码里基本就可用-少数可能需要微调 ("TeraCopy.exe", "copy", `*"e:\1.txt"`, `"e:\a\"`) 没用过 tera ,不知道*"e:\1.txt" 为什么要这样写,但是双引号里可能需要转义才对,例如 e:\\1.txt `"e:\a\"` ,这种写法 我觉得就是错误的,直接`e:\a\` 说不定还可以 如果双引号是程序必须的参数,可以试试 "copy", `*"e:\\1.txt"` `e:\a\` 你最好发一遍可以正确执行的命令,大家可以帮你看看 最后再重申这跟 golang 无关,你用其他语言也可能遇到一样的问题 |
54 gam2046 2022-04-09 15:19:48 +08:00 @singerll #40 大佬 我也是近期新学的 golang ,但是可能受其他语言影响,golang 设计的异常判断 if _, err := something; err == nil {...} 就是这种是标准的处理方法嘛?总感觉写起来怪怪的。 |
55 GeruzoniAnsasu 2022-04-09 15:26:10 +08:00 |
56 gam2046 2022-04-09 15:56:19 +08:00 @GeruzoniAnsasu #55 唔,好吧。就是我比较不能适应的是这种写法 if _,err:= ... ; err != nil{ ... } 一个方法中有好多 if err != nil ,相比其他语言的 try catch ,一些兜底的错误处理,可以统一放在 catch 里。 我也不太明白是我理解不透彻嘛 |
57 whyso 2022-04-09 17:46:02 +08:00 说实话,这种错误我都不好意思贴出来给大家看。。。 |
![]() | 59 lysS 2022-04-09 19:10:54 +08:00 还有三目,估计楼主没有写过业务。常用的三目大概长这样 const word = (res.distance === 0) ? 'a' : (res.distance === 1 && res.difference > 3) ? 'b' : (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c' : 'd'; |
![]() | 60 fyibmsd 2022-04-09 19:32:18 +08:00 一个都没黑到点子上 |
![]() | 61 KotlinAmai 2022-04-09 21:29:49 +08:00 const TeraCopy = "D:\\TeraCopy\\TeraCopy.exe" func main() { copyPaths := os.Args[1] targetDir := os.Args[2] command := exec.Command(TeraCopy, "copy", fmt.Sprintf("*%s", copyPaths), targetDir) if err := command.Run(); err != nil { panic(err) } } 可以这样写,亲测可行 TeraCopy.exe copy *"G:\1 source.txt" "G:\target\" 等价于 TeraCopy.exe copy "*G:\1 source.txt" "G:\target\" exec.Command 传递参数的时候,不需要引号括起来 |
![]() | 62 KotlinAmai 2022-04-09 21:32:54 +08:00 终端环境的参数两边的引号,是由终端进行处理的。传递进程序,是不带两边的引号的 |
![]() | 63 KousukeSakurako 2022-04-09 23:54:29 +08:00 via iPhone 怎么回事,黑不到点子上啊我看着都急 |
64 kkbblzq 2022-04-10 07:56:48 +08:00 说实话,前半段看下来还好,但是你加了后半段,看起来就很尴尬了,因为非常明显的报错,感觉这不是 go 不 go 的问题了,换个语言报错你确定你能看得出来? |
65 borpubi 2022-04-12 16:37:12 +08:00 对于一个伪 IT 来说,三元运算符确实没有 if 易读易懂好解释。 |