How to write a string in a Scala process?

I am starting and starting a Scala process.

    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)

The process reads and writes to standard IO (console). How can I send a string command to a process if it is already running?

The Scala process API has a ProcessBuilder, which in turn is a collection of useful methods. But ProcessBuilder is used before the process begins to compose complex shell commands. In addition, Scala has a ProcessIO for handling input or output. I don’t need that either. I just need to send a message to my process.

In Java, I would do something like this.

        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 just for example
        writer.write("quit");  // send to the process command to stop working
        writer.newLine();
        writer.flush();

It works very well. I start my process, get InputStream and OutputStream from it, and use streams to interact with the process.

Scala . ProcessBuilder . ProcessIO IO.

Scala ?

UPDATE:

, 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, .

+4
3

, Scala ( , ProcessIO) . , API, , i/o .

, - , , , . - : bc , stdout. - - ( Scala, ):

$ 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 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 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).

+1

, , ProcessIO , , Java.

0

, :

object demo {
  import scala.sys.process._

  def getIO = {
    // create piped streams that can attach to process streams:
    val procInput = new java.io.PipedOutputStream()
    val procOutput = new java.io.PipedInputStream()
    val io = new ProcessIO(
      // attach to the process internal input stream
      { in =>
        val istream = new java.io.PipedInputStream(procInput)
        val buf = Array.fill(100)(0.toByte)
        var br = 0
        while (br >= 0) {
          br = istream.read(buf)
          if (br > 0) { in.write(buf, 0, br) }
        }
        in.close()
      },
      // attach to the process internal output stream
      { out =>
        val ostream = new java.io.PipedOutputStream(procOutput)
        val buf = Array.fill(100)(0.toByte)
        var br = 0
        while (br >= 0) {
          br = out.read(buf)
          if (br > 0) { ostream.write(buf, 0, br) }
        }
        out.close()
      },
      // ignore stderr
      { err => () }
    )
    // run the command with the IO object:
    val cmd = List("awk", "{ print $1 + $2 }")
    val proc = cmd.run(io)

    // wrap the raw streams in formatted IO objects:
    val procO = new java.io.BufferedReader(new java.io.InputStreamReader(procOutput))
    val procI = new java.io.PrintWriter(procInput, true)
    (procI, procO)
  }
}

. , , , /, , ..

scala> :load /home/eje/scala/input2proc.scala
Loading /home/eje/scala/input2proc.scala...
defined module demo

scala> val (procI, procO) = demo.getIO
procI: java.io.PrintWriter = java.io.PrintWriter@7e809b79
procO: java.io.BufferedReader = java.io.BufferedReader@5cc126dc

scala> procI.println("1 2")

scala> procI.println("3 4")

scala> procI.println("5 6")

scala> procI.close()

scala> procO.readLine
res4: String = 3

scala> procO.readLine
res5: String = 7

scala> procO.readLine
res6: String = 11

scala> 

In general, if you simultaneously control the input and output in one thread at the same time, there is a possibility of blocking, since reading or writing can block the expectation of another. It is most secure to execute input logic and output logic in your threads. Given these problems with threads, you can also simply enter input and output logic directly into the definitions { in => ... }and { out => ... }, since they both start in separate threads automatically

0
source

Source: https://habr.com/ru/post/1666150/


All Articles