使用Scala的sys.process API调用带引号字符串命令遇问题
Scala中sys.process调用emacsclient与终端执行结果不一致的问题
我之前碰到过类似的场景,也研究过Scala sys.process库的命令解析逻辑,你遇到的这个情况其实不是库的bug,而是Scala处理带嵌套引号的命令时,和终端shell的解析规则不一样导致的。
先还原你遇到的问题场景:
~> scala Welcome to Scala 2.12.6 (OpenJDK 64-Bit Server VM, Java 1.8.0_172). Type in expressions for evaluation. Or try :help. scala> import sys.process._ import sys.process._ scala> """emacsclient --eval '(+ 4 5)'""".! *ERROR*: End of file during parsing res0: Int = 1 scala> :quit ~> emacsclient --eval '(+ 4 5)' 9
问题原因
终端直接执行命令时,shell会帮你处理外层引号,把'(+ 4 5)'作为一个完整的参数传递给emacsclient;但Scala的sys.process在处理单个字符串形式的命令时,只会简单按空格拆分参数,不会识别shell的嵌套引号规则。这样一来,emacsclient实际收到的参数是--eval、'(+、4、5)',这显然不符合Lisp表达式的语法要求,所以会报解析错误。
解决方法
推荐用sys.process的序列式调用方式,把每个参数单独作为序列的元素,这样就能保证参数被正确传递:
import sys.process._ Seq("emacsclient", "--eval", "(+ 4 5)").!
这种方式下,Scala会将序列中的每个元素作为独立的命令参数传递给emacsclient,和终端直接执行的效果完全一致,能得到正确的返回结果9。
如果坚持要使用字符串形式的命令,也可以通过调用shell来间接执行,让shell帮你处理引号解析:
"""sh -c "emacsclient --eval '(+ 4 5)'" """.!
不过这种方式需要额外启动shell进程,不如序列式调用简洁高效,所以更推荐第一种方案。
你提到已经在GitHub提交了issue,其实这是sys.process的设计逻辑——单个字符串命令的解析是极简的空格拆分,而序列式调用才是处理复杂参数(带空格、引号的参数)的标准方式,并不是bug哦。
内容的提问来源于stack exchange,提问作者SongWithoutWords
相关产品推荐
相关产品推荐

