Reputation: 581
It is to my understanding that Scala can run system commands and receive their output. I am working on writing a web client for a system command that I have, so that being said I need to perform the command, receive the output, based on the output I can give it a command. I want to keep doing this until the user kills the command. I have read a bit about ProcessIO and I have gotten as far as getting the command to run from scala and receiving the output, but how can I give it input?
EDIT: What I am looking for is, I call a command with scala. The command I call asks for a input, the user supplies the input to the scala program with then passes that to the called program.
An Example:
Scala Program -> Calls System Program -> System Program ask for username and password -> Scala Program program then asks for username and password from user and user supplies input -> Scala program passes inputs to System Program.
I would like to keep the process alive while feeding it input.
Upvotes: 4
Views: 1148
Reputation: 2514
I can't tell from your question if you intend for the user to supply inputs with something other than stdin to the console. While I suspect you'd like this to be "fully contained" in the Scala program, I haven't been able to work that out yet. However, if using the console is acceptable, here's an example of a simple Scala program that asks for a username/password and and another Scala program that starts it and uses Process.run(true)
to wire the invoked program's out/err to the console while the input can be supplied to the console.
SimpleProgram to test taking inputs:
package so
import java.util.Scanner
object SimpleProgram extends App {
def getInput(prompt: String): Option[String] = {
print( s"$prompt: " )
val sc = new Scanner(System.in)
sc.hasNextLine match {
case true => val out = sc.nextLine
if( out.length > 1 ) Some(out) else None
case _ => None
}
}
while( true ) {
(getInput("username"), getInput("password")) match {
case (Some(u), Some(p)) => println( s"Logged in as $u" ); System.exit(0)
case _ => println( "Invalid input. Please try again." )
}
}
}
And here's the program calling ProcessBuilder( where the classpath won't work w/o alterations ):
package so
import scala.sys.process._
object ProcessBuilderTest extends App {
val classpath = "<path to>/scala-library.jar:./classes"
val pb = Process("java", Seq("-cp", classpath, "so.SimpleProgram" ))
pb.run(true) // all the magic happens here.
}
In this case, the Process
is basically just wrapping the invoked program in a ProcessBuilder
. I haven't been able to work out using a ProcessIO
with supplied methods to both eat the appropriate chars, and still kill the streams etc. My guess is that looking at the working run(true)
case would be instructive.
Here's an example of the console logging from running the latter with a corrected classpath:
username: foo
password:
Invalid input. Please try again.
username: foo
password: bar
Logged in as foo
I'm using "java" to run the Scala code because I don't have Scala installed on my mac other than through Eclipse. From Eclipse, ProcessBuilderTest
was run from the project directory with both classes, and the output directory set to "classes" instead of "bin".
Upvotes: 1
Reputation: 20435
Consider the following example with redirection,
import scala.sys.process._
import java.io.File
"""echo -e hello\nworld""" #> new File("hello") !
new File ("hello") #> """grep world -c""" !!
which delivers 1
.
This writes an echoed string onto an output file; next the now input file is redirected to a system command.
Update
Command
"""echo -e hello\nworld""" #> """grep world -c""" !!
uses redirection and delivers result as a string. This avoids intermediate files.
Upvotes: 4