如何在 scala sys.process 调用上获得 shell 扩展

How to get shell expansion on scala sys.process invocations

考虑 shell 扩展的简单尝试:

Simple/direct方法:

scala> ("/bin/ls /tmp/*" run BasicIO(false, sb, None)).exitValue
ls: /tmp/*: No such file or directory
res18: Int = 1

我尝试了 ProcessIO、BasicIO、Process 等的多种组合,但无法弄清楚如何让 shell 扩展正常工作。

bash -c :

scala> ("bash -c \"/bin/ls /tmp/*\"" run BasicIO(false, sb, None)).exitValue
/tmp/*": -c: line 0: unexpected EOF while looking for matching `"'
/tmp/*": -c: line 1: syntax error: unexpected end of file
res19: Int = 2

管道到 bash -s :

scala> ("echo \"/bin/ls /tmp/*\" | bash -s") run BasicIO(false, sb, None)).exitValue
<console>:1: error: ';' expected but ')' found.
       ("echo \"/bin/ls /tmp/*\" | bash -s") run BasicIO(false, sb, None)).exitValue

顺便说一下,shell 中的最后一个看起来像下面这样(并且有效):

21:28:32/dstat $echo "/bin/ls /tmp/*" | bash -s

/tmp/OSL_PIPE_501_SingleOfficeIPC_a974a3af70d46eaeed927022833718b7
/tmp/oobelib.log
/tmp/spark-steve-org.apache.spark.deploy.master.Master-1.pid
/tmp/spark-steve-org.apache.spark.deploy.worker.Worker-1.pid
/tmp/KSOutOfProcessFetcher.501.qQkpPp2uZLdVc5pukHmfJMR4bkM=:

Shell 转义也有助于理解 wrt scala Process 类:包含扩展和转义的示例将是最佳的。

UPDATE 我找到了这个 JIRA - 它可能是相关的。我希望不会 - 这意味着 little/no 希望此处描述的功能..

sys.process._ 可以接受的内容非常有限,无法使用 https://issues.scala-lang.org/browse/SI-7027

另一个更新 我发现了一个涉及尊敬的 Daniel Sobral 的旧电子邮件线程,他提到:

Because the quotes are not delimiting the parameter passed to bash -- it is Scala who decides how the arguments break up, and it simply splits on spaces, without any quotation facility. If you try the following, instead, it will work:

Seq("bash", "-c", "ls *.scala").!

"fire and forget" 版本的 运行 和 shell 命令看起来更加严峻。我向往ruby

 %x{whatever shell string you want goes here}

例如

echo 'print %x{ls -lrtad /etc/* 2>&1}' | ruby

哪个最满意returns:

-r--r--r--   1 root   wheel          69836 May 28  2013 /etc/php.ini.default-

5.2-previous~orig
lrwxr-xr-x   1 root   wheel             30 Oct 22  2013 /etc/localtime -> /usr/share/zoneinfo/US/Pacific
-rw-r--r--   1 root   wheel            102 Nov  5  2013 /etc/hostconfig
-rw-r--r--   1 root   wheel           1286 Nov  5  2013 /etc/my.cnf
-rw-r--r--   1 root   wheel           4161 Dec 18  2013 /etc/sshd_config~previous
-rw-r--r--   1 root   wheel            199 Feb  7  2014 /etc/shells
-rw-r--r--   1 root   wheel              0 Sep  9  2014 /etc/xtab
-rw-r--r--   1 root   wheel           1316 Sep  9  2014 /etc/ttys
  .. etc

但看起来 Scala 没有发生..

恐怕您误会了我的回答。 Ruby 正在做同样的事情,我不用看他们的代码就知道这一点,因为 Java(以及扩展的 Scala)呈现为 API是直接翻译Unix的API.

shell 进行了 shell 扩展,虽然任何其他软件完全有可能模仿它们,但这将是一场失败的游戏.经常提供通配符,但它们只是 shell 扩展的一小部分。

我的回答包含您需要的一切,但让我进一步说明:

import scala.sys.process._
implicit class RubyX(val sc: StringContext) extends AnyVal {
  def x(args: Any*): ProcessBuilder = {
    val strings = sc.parts.iterator
    val expressions = args.iterator
    var buf = new StringBuffer(strings.next)
    while(strings.hasNext) {
      buf append expressions.next
      buf append strings.next
    }
    Process(Seq("bash", "-c", buf.toString))
  }
}

那你就可以了

x"ls *.scala".!

我返回了一个 ProcessBuilder,因此您可以选择最适合您的执行形式,例如 ! 上面 returns 退出代码并将其他所有内容回显到标准输出。