【问题标题】:How does the “scala.sys.process” from Scala 2.9 work?Scala 2.9 中的“scala.sys.process”是如何工作的?
【发布时间】:2011-05-16 05:14:07
【问题描述】:

我刚刚查看了新的scala.sysscala.sys.process 包,看看这里是否有帮助。但是,我完全不知所措。

有人有关于如何实际启动流程的示例吗?

还有,我最感兴趣的是:你能分离进程吗?

当父进程结束时,分离的进程将继续运行,是 Ant 的弱点之一。

更新:

分离是什么似乎有些混乱。从我当前的项目中有一个真实的例子。一次使用 z-Shell,一次使用 TakeCommand:

Z 壳:

if ! ztcp localhost 5554; then
    echo "[ZSH] Start emulator"
    emulator                        \
    -avd    Nexus-One               \
    -no-boot-anim                   \
    1>~/Library/Logs/${PROJECT_NAME}-${0:t:r}.out   \
    2>~/Library/Logs/${PROJECT_NAME}-${0:t:r}.err   &
    disown
else
    ztcp -c "${REPLY}"
fi;

接受命令:

IFF %@Connect[localhost 5554] lt 0 THEN
   ECHO [TCC] Start emulator
   DETACH emulator -avd Nexus-One -no-boot-anim
ENDIFF

在这两种情况下,它都是一劳永逸的,模拟器已启动,并且即使在脚本结束后仍将继续运行。当然,必须编写两次脚本是一种浪费。所以我现在研究 Scala 以实现没有 cygwin 或 xml 语法的统一进程处理。

【问题讨论】:

  • disown 真的是一个 shell 的东西,而不是一个 Unix 的东西。它所做的只是避免在退出时向子进程发送 SIGHUP 的 shell 行为。

标签: scala


【解决方案1】:

第一次导入:

import scala.sys.process.Process

然后创建一个 ProcessBuilder

val pb = Process("""ipconfig.exe""")

那么你有两个选择:

  1. 运行并阻塞直到进程退出

    val exitCode = pb.!
    
  2. 在后台运行进程(分离)并获得一个Process实例

    val p = pb.run
    

    然后你可以从进程中获取退出代码(如果进程仍在运行,它会阻塞直到它退出)

    val exitCode = p.exitValue
    

如果要处理进程的输入输出可以使用ProcessIO:

import scala.sys.process.ProcessIO
val pio = new ProcessIO(_ => (),
                        stdout => scala.io.Source.fromInputStream(stdout)
                          .getLines.foreach(println),
                        _ => ())
pb.run(pio)

【讨论】:

  • 谢谢。很好的例子。将帮助我处理一些重复的脚本。请注意,我正在寻找的(用 unix 术语)是“否认”。看看我刚刚添加的示例。
  • 对于 I/O 处理,还有一些不错的 #< #> 方便方法。可惜#< (s: String) 不见了
  • 我已经接受了这个答案,因为它包含我用来让这里的文档正常工作的 ProcessIO,这使得这个答案最有用。
  • 是获取exitCode 和字符串输出以使用ProcessIO 的唯一方法吗?
  • 但是如果我们在进程仍在后台运行时需要 exitValue 怎么办,即进程将永远运行,但我们也需要正在运行的进程中的 exitValue
【解决方案2】:

有没有人举个例子 实际启动一个进程?

import sys.process._ // Package object with implicits!
"ls"!

而且,这对我来说最有趣的是: 你能分离进程吗?

"/path/to/script.sh".run()

你要做的大部分事情都与sys.process.ProcessBuilder 相关,这个特征。了解一下。

有一些隐式可以使用法不那么冗长,它们可以通过包对象sys.process 获得。导入其内容,如示例中所示。另外,请查看它的 scaladoc。

【讨论】:

    【解决方案3】:

    我很确定分离的进程工作得很好,考虑到你必须明确地等待它退出,并且你需要使用线程来照看标准输出和标准错误。这是非常基本的,但这是我一直在使用的:

    /** Run a command, collecting the stdout, stderr and exit status */
    def run(in: String): (List[String], List[String], Int) = {
      val qb = Process(in)
      var out = List[String]()
      var err = List[String]()
    
      val exit = qb ! ProcessLogger((s) => out ::= s, (s) => err ::= s)
    
      (out.reverse, err.reverse, exit)
    }
    

    【讨论】:

    • 这看起来很有帮助。我现在理解了语法,这比我以前做的要多。只有我在寻找启动一个进程并让它在脚本结束后运行。
    • 我在 scala 中使用 Process 运行 postgres 脚本文件,由于脚本文件输出的巨大输出,我的程序卡住了,在阅读了 100 篇博客之后,这是唯一对我有用的答案,感谢一百万次@Alex Cruise
    【解决方案4】:

    如果我理解到目前为止的对话,原始问题的一个方面尚未得到回答:

    1. 如何“分离”生成的进程,使其继续独立于父 scala 脚本运行

    主要的困难是所有涉及生成进程的类都必须在 JVM 上运行,并且当 JVM 退出时它们不可避免地会被终止。但是,一种解决方法是通过利用 shell 代表您执行“分离”来间接实现目标。以下启动 gvim 编辑器的 scala 脚本似乎可以正常工作:

    val cmd = 列表( “斯卡拉”, “-e”, """import scala.sys.process._ ; "gvim".run ; System.exit(0);""" ) val proc = cmd.run

    它假定 scala 在 PATH 中,并且它确实(不可避免地)让 JVM 父进程也运行。

    【讨论】:

      【解决方案5】:

      进程是从 SBT 导入的。这是关于如何使用流程库的完整指南它出现在 SBT 中

      https://github.com/harrah/xsbt/wiki/Process

      【讨论】:

      • 有趣,!到了最后。我永远不会仅从 scaladoc 中猜到它。
      • 看起来文档不是最新的,因为现在需要使用“import scala.sys.process._”来使用隐式转换。
      • 是的,请参阅 Scala 2.9 发行说明 (scala-lang.org/node/9483) -“scala.sys 和 scala.sys.process,它们是从 sbt.Process 导入的。”。即,包已更改。
      【解决方案6】:

      如果这里有文档,以下功能将允许使用:

      def #<<< (command: String) (hereDoc: String) =
      {
          val process = Process (command)
          val io = new ProcessIO (
              in  => {in.write (hereDoc getBytes "UTF-8"); in.close},
              out => {scala.io.Source.fromInputStream(out).getLines.foreach(println)},
              err => {scala.io.Source.fromInputStream(err).getLines.foreach(println)})
          process run io
      }
      

      遗憾的是,我无法(没有时间)使其成为中缀操作。因此,建议的调用约定是:

      #<<< ("command") {"""
      Here Document data
      """}
      

      如果有人能给我一个提示,告诉我如何使它更像是一个 shell,那就是 call:

      "command" #<<< """
      Here Document data
      """ !
      

      【讨论】:

      • implicit class HereDocCommand(command: String) { def #&lt;&lt;&lt;(hereDoc: String) = ... }
      【解决方案7】:

      记录过程稍微好一点在我的列表中排在第二位大概有两个月了。你可以从我从未接触过的事实推断出我的名单。与大多数我不做的事情不同,这是我说我会做的事情,所以我非常遗憾它仍然像它到达时一样没有记录。剑,准备好!我倒在你身上!

      【讨论】:

        猜你喜欢
        • 2011-09-13
        • 2011-10-25
        • 2023-03-25
        • 1970-01-01
        • 1970-01-01
        • 2018-10-07
        • 1970-01-01
        • 2013-02-12
        • 1970-01-01
        相关资源
        最近更新 更多