How does the “scala.sys.process” from Scala 2.9 work?

前端 未结 7 1085
甜味超标
甜味超标 2020-11-30 18:09

I just had a look at the new scala.sys and scala.sys.process packages to see if there is something helpful here. However, I am at a complete loss.<

相关标签:
7条回答
  • 2020-11-30 18:23

    First import:

    import scala.sys.process.Process
    

    then create a ProcessBuilder

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

    Then you have two options:

    1. run and block until the process exits

      val exitCode = pb.!
      
    2. run the process in background (detached) and get a Process instance

      val p = pb.run
      

      Then you can get the exitcode from the process with (If the process is still running it blocks until it exits)

      val exitCode = p.exitValue
      

    If you want to handle the input and output of the process you can use ProcessIO:

    import scala.sys.process.ProcessIO
    val pio = new ProcessIO(_ => (),
                            stdout => scala.io.Source.fromInputStream(stdout)
                              .getLines.foreach(println),
                            _ => ())
    pb.run(pio)
    
    0 讨论(0)
  • 2020-11-30 18:32

    Process was imported from SBT. Here's a thorough guide on how to use the process library as it appears in SBT.

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

    0 讨论(0)
  • 2020-11-30 18:33

    Documenting process a little better was second on my list for probably two months. You can infer my list from the fact that I never got to it. Unlike most things I don't do, this is something I said I'd do, so I greatly regret that it remains as undocumented as it was when it arrived. Sword, ready yourself! I fall upon thee!

    0 讨论(0)
  • 2020-11-30 18:42

    The following function will allow easy use if here documents:

    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
    }
    

    Sadly I was not able to (did not have the time to) to make it an infix operation. Suggested calling convention is therefore:

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

    It would be call if anybody could give me a hint on how to make it a more shell like call:

    "command" #<<< """
    Here Document data
    """ !
    
    0 讨论(0)
  • 2020-11-30 18:44

    I'm pretty sure detached processes work just fine, considering that you have to explicitly wait for it to exit, and you need to use threads to babysit the stdout and stderr. This is pretty basic, but it's what I've been using:

    /** 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)
    }
    
    0 讨论(0)
  • 2020-11-30 18:44

    If I understand the dialog so far, one aspect of the original question is not yet answered:

    1. how to "detach" a spawned process so it continues to run independently of the parent scala script

    The primary difficulty is that all of the classes involved in spawning a process must run on the JVM, and they are unavoidably terminated when the JVM exits. However, a workaround is to indirectly achieve the goal by leveraging the shell to do the "detach" on your behalf. The following scala script, which launches the gvim editor, appears to work as desired:

    val cmd = List(
       "scala",
       "-e",
       """import scala.sys.process._ ; "gvim".run ; System.exit(0);"""
    )
    val proc = cmd.run
    

    It assumes that scala is in the PATH, and it does (unavoidably) leave a JVM parent process running as well.

    0 讨论(0)
提交回复
热议问题