Scala - shell commands with pipe - scala

I'm a Scala beginner and I'm writing a wrapper for invoking shell commands. Currently I'm trying to invoke shell commands with pipes from a specified directory.
To achieve this I wrote simple utility:
def runCommand(command: String, directory: File): (Int, String, String) = {
val errbuffer = new StringBuffer();
val outbuffer = new StringBuffer();
//run the command
val ret = sys.process.Process(command, directory) !
//log output and err
ProcessLogger(outbuffer append _ + "\n", outbuffer append _ + "\n");
return (ret, outbuffer.toString(), errbuffer.toString());
}
However with this utility I can't use pipes, for example:
runCommand("ps -eF | grep -i foo", new File("."));
First I thought, that pipes are shell's functionality, so I tried "/bin/sh -c ps -eF | grep -i foo", but it seems that expression from the right of the pipe was ignored.
I also tried running commands with ! syntax (sys.process._ package), but I couldn't figure out, how to call command from specified directory (without using "cd").
Could you please advice me, how to do this correctly?

Change
val ret = sys.process.Process(command, directory) !
to
val ret = sys.process.stringSeqToProcess(Seq("/bin/bash", "-c", "cd " + directory.getAbsolutePath + ";" + command))
Or you could directly use the magic provided by Scala:
import.scala.sys.process._
val ret = "ps -ef" #| "grep -i foo" !

Related

gawk command from scala gives invalid character in expression error

Below is the sample program, that is generating a gwak command and executing it from scala.
Generated command is giving "invalid character in expression error"
If the same command is executed directly from macOS commandline, it works without error.
package org.mogli.pup.main
object GAwkSample {
def main(args: Array[String]): Unit = {
val text = "hello world"
val home = sys.env("HOME")
val cmnd = s"gawk -i inplace 'NR==7{print " + "\"" + text + "\"" + s"}1' ${home}/FirstEg.txt"
println(s"$cmnd")
import sys.process._
s"$cmnd" !
}
}
Output of above scala program :-
gawk -i inplace 'NR==7{print "hello world"}1' /Users/mogli/FirstEg.txt
gawk: cmd.
line:1: 'NR==7{print gawk: cmd. line:1: ^ invalid char ''' in
expression

Execute shell script from scala application

I want to execute the sh file from Scala application.
Let's say I have createPassword.sh file and I need to invoke this sh file from Scala application and get the output back.
How can I achieve through scala application?
This should do the trick if the script is in the current working directory (otherwise specify the full path of the script)
import sys.process._
val result = "./createPassword.sh" !!
result is then a String containing the standard output (and standard error)
EDIT: If you want to use ProcessBuillder from Java SE7, you can also use this in scala:
import java.io.{BufferedReader, InputStreamReader}
val p = new ProcessBuilder("/bin/bash","createPassword.sh")
val p2 = p.start()
val br = new BufferedReader(new InputStreamReader(p2.getInputStream()))
var line:String = ""
while ({line = br.readLine(); line!= null}) {
println(line)
}
Given your dir has a script,
`val path = "./src/test/tests/Integration/"`
`val output = Process("sh test.sh", new File("path")).!!`

How to execute system commands in scala

i am new at scala and i am trying to run this simple program that get input from the user and execute it in the operation system:
import scala.io._
import sys.process._
object MyCmd {
def main(args: Array[String]) = {
print("> ")
var inputString = StdIn.readLine()
while(!inputString.trim().equals("exit")) {
var proc = stringToProcess(inputString)
println( proc.!!)
print("> ")
inputString = StdIn.readLine()
}
}
}
but when i'm running it:
c:\IDE\scala\test>scala MyCmd
> dir
java.io.IOException: Cannot run program "dir": CreateProcess error=2, The
system cannot find the file specified
...
Any help will be much appreciate
sys.process.ProcessBuilder not runnig Windows cmd command.
See Executing shell commands from Scala REPL
If you need to use the cmd command, you can execute as
val proc = stringToProcess("cmd /C "+inputString)
println(proc.!!)

How to run external process in Scala and get both exit code and output?

How to call an external process and read both of its exit code and standard out, once it finished?
Using sys.Process will result in an exception being thrown on different exit code than 0 for success.
Try this:
import sys.process._
val stdout = new StringBuilder
val stderr = new StringBuilder
val logger = ProcessLogger(stdout append _, stderr append _)
val status = "ls -al " ! logger
println(status)
println("stdout: " + stdout)
println("stderr: " + stderr)
Then you got both of them: status, stdout and stderr.
Have you looked at Process.exitValue?
Returns the exit value for the subprocess.
(I've asked this question on freenode #java and was requested to post here if I found a solution, so here goes)
Simple approach is to use sys.ProcessBuilder:
def RunExternal(executableName: String, executableDir: String) : (Int, List[String]) = {
val startExecutionTime = System.currentTimeMillis()
val pb : ProcessBuilder = new ProcessBuilder (executableName)
pb.directory(new java.io.File(executableDir))
val proc = pb.start()
proc.waitFor()
val exitCode = proc.exitValue()
val output = scala.io.Source.fromInputStream(proc.getInputStream).getLines.toList
val executionTime = System.currentTimeMillis() - startExecutionTime
logger.info(String.format(s"Process exited with exit code: ${exitCode}."))
logger.info(String.format(s"Process took ${executionTime} milliseconds."))
(exitCode, output)
}

Using scala.sys.process with timeout

I find it extreemly cool to use standard syntax like
import scala.sys.process._
val countLogger = ProcessLogger(line => {println ("out line: " + line)},
line => {println ("err line: " + line)})
val exitCode = ("cat prog.c" #&& "gcc prog.c -o prog -lm"
#&& "echo running, this may hang" #&& "prog.exe") ! countLogger
println("exitCode = " + exitCode)
It however happens that last process hangs. Is it possible to kill it on timeout?
You can wrap your process in a Future(blocking(_)) and if it doesn't return after the time-out, you call process.destroy().
That's what I have done for my small Processor library, e.g. see here. Instead of using ! to eagerly wait for the exit-code, you use the run method. Here is an adaption from the README:
import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.sys.process._
val p = "sleep 100".run() // start asynchronously
val f = Future(blocking(p.exitValue())) // wrap in Future
val res = try {
Await.result(f, duration.Duration(2, "sec"))
} catch {
case _: TimeoutException =>
println("TIMEOUT!")
p.destroy()
p.exitValue()
}