如何将字符串写入Scala Process?

我开始并运行
Scala进程.

    val dir = "/path/to/working/dir/"
    val stockfish = Process(Seq("wine", dir + "stockfish_8_x32.exe"))
    val logger = ProcessLogger(printf("Stdout: %s%n",  _))
    val stockfishProcess = stockfish.run(logger, connectInput = true)

该过程从标准IO(控制台)读取和写入.如果已经启动过程,如何向进程发送字符串命令?

Scala进程API具有ProcessBuilder,而ProcessBuilder又有许多有用的方法.但是在进程开始组成复杂的shell命令之前使用ProcessBuilder. Scala还有ProcessIO来处理输入或输出.我也不需要它.我只需要向我的进程发送消息.

在Java中我会做这样的事情.

        String dir = "/path/to/working/dir/";
        ProcessBuilder builder = new ProcessBuilder("wine", dir + "stockfish_8_x32.exe");
        Process process = builder.start();

        OutputStream stdin = process.getOutputStream();
        InputStream stdout = process.getInputStream();

        BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));

        new Thread(() -> {
            try {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println("Stdout: " + line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        Thread.sleep(5000); // it's just for example
        writer.write("quit");  // send to the process command to stop working
        writer.newLine();
        writer.flush();

它运作得很好.我启动我的进程,从中获取InputStream和OutputStream,并使用流与进程交互.

似乎Scala Process trait没有提供写入它的方法.进程运行后,ProcessBuilder无用.而ProcessIO仅用于IO捕获和处理.

有没有办法写Scala运行过程?

更新:

我不知道如何使用ProcessIO将字符串传递给正在运行的进程.
我做了以下.

import scala.io.Source
import scala.sys.process._

object Sample extends App {

   def out = (output: java.io.OutputStream) => {
      output.flush()
      output.close()
   }

   def in = (input: java.io.InputStream) => {
      println("Stdout: " + Source.fromInputStream(input).mkString)
      input.close()
   }

   def go = {
      val dir = "/path/to/working/dir/"
      val stockfishSeq = Seq("wine", dir + "/stockfish_8_x32.exe")
      val pio = new ProcessIO(out, in, err => {})
      val stockfish = Process(stockfishSeq)
      stockfish.run(pio)

      Thread.sleep(5000)
      System.out.write("quit\n".getBytes)
      pio.writeInput(System.out) // "writeInput" is function "out" which I have passed to conforming ProcessIO instance. I can invoke it from here. It takes OutputStream but where can I obtain it? Here I just pass System.out for example.
   }
   go
 }

当然它不起作用,我无法理解如何实现上面的Java片段中的功能.很高兴有Scala代码的建议或片段清除我的问题.

最佳答案 我认为围绕Scala流程的文档(特别是ProcessIO的用法和语义)可以使用一些改进.我第一次尝试使用这个API时,我发现它非常令人困惑,并且需要一些试验和错误才能让我的子进程i / o正常工作.

我想看到一个简单的例子可能就是你真正需要的.我会做一些非常简单的事情:调用bc作为子进程来进行一些简单的计算,然后将答案打印到我的标准输出.我的目标是做这样的事情(但是来自Scala,而不是来自我的shell):

$printf "1+2\n3+4\n" | bc
3
7

这是我在Scala中的表现:

import scala.io.Source
import scala.sys.process._

object SimpleProcessExample extends App {

  def out = (output: java.io.OutputStream) => {
    output.flush()
    output.close()
  }

  def in = (input: java.io.InputStream) => {
    println("Stdout: " + Source.fromInputStream(input).mkString)
    input.close()
  }

  // limit scope of any temporary variables
  locally {
    val calcCommand = "bc"
    // strings are implicitly converted to ProcessBuilder
    // via scala.sys.process.ProcessImplicits.stringToProcess(_)
    val calcProc = calcCommand.run(new ProcessIO(
      // Handle subprocess's stdin
      // (which we write via an OutputStream)
      in => {
        val writer = new java.io.PrintWriter(in)
        writer.println("1 + 2")
        writer.println("3 + 4")
        writer.close()
      },
      // Handle subprocess's stdout
      // (which we read via an InputStream)
      out => {
        val src = scala.io.Source.fromInputStream(out)
        for (line <- src.getLines()) {
          println("Answer: " + line)
        }
        src.close()
      },
      // We don't want to use stderr, so just close it.
      _.close()
    ))

    // Using ProcessBuilder.run() will automatically launch
    // a new thread for the input/output routines passed to ProcessIO.
    // We just need to wait for it to finish.

    val code = calcProc.exitValue()

    println(s"Subprocess exited with code $code.")

  }
}

请注意,您实际上并不直接调用ProcessIO对象的任何方法,因为它们是由ProcessBuilder自动调用的.

这是结果:

$scala SimpleProcessExample
Answer: 3
Answer: 7
Subprocess exited with code 0.

如果您希望输入和输出处理程序与子进程之间进行交互,则可以使用标准线程通信工具(例如,两者都接近BlockingQueue的实例).

点赞