Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using scala sys.process with single quotes, white-space, pipes etc

Tags:

curl

scala

I am trying to use scala.sys.process._ to submit a POST request to my chronos server with curl. Because there is white space in the command's arguments, I am using the Seq[String] variant of cmd.!!

I am building the command like so:

val cmd = Seq("curl", "-L", "-X POST", "-H 'Content-Type: application/json'", "-d " + jsonHash,  args.chronosHost + "/scheduler/" + jobType)

which produces, as expected,

cmd: Seq[String] = List(curl, -L, -X POST, -H 'Content-Type: application/json', -d '{"schedule":"R/2014-02-02T00:00:00Z/PT24H", "name":"Scala-Post-Test", "command":"which scalac", "epsilon":"PT15M", "owner":"[email protected]", "async":false}', localhost:4040/scheduler/iso8601)

however, running this appears to mangle the 'Content-Type: application/json' argument:

scala> cmd.!!
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   264    0   100  100   164   2157   3538 --:--:-- --:--:-- --:--:-- 54666
res21: String =
"The HTTP header field "Accept" with value "*/* 'Content-Type:application/json'" could not be parsed.
"

which I don't understand. By contrast, calling cmd.mkString(" ") and copy+pasting into the terminal works as expected.

curl -L -X POST -H 'Content-Type:application/json' -d '{"schedule":"R/2014-02-02T00:00:00Z/PT24H", "name":"Scala-Post-Test", "command":"which scalac", "epsilon":"PT15M", "owner":"[email protected]", "async":false}' mapr-01.dev.quantifind.com:4040/scheduler/iso8601

I have tried numerous variations on the -H argument to no avail, any insight into using single quotes in sys.process._'s !! would be greatly appreciated.

I have tried variations on this as well, which generates a slew of errors, including

<h2>HTTP ERROR: 415</h2>
<p>Problem accessing /scheduler/iso8601. Reason:
<pre>    Unsupported Media Type</pre></p>
<hr /><i><small>Powered by Jetty://</small></i>

(in addition to butchering the jsonHash, ie:

[1/6]: '"schedule":"R/2014-02-02T00:00:00Z/PT24H"' --> <stdout>

curl: (6) Couldn't resolve host ''"schedule"'

Which makes me think it is not interpreting the -H argument correctly
like image 547
Austin Avatar asked Jan 21 '14 01:01

Austin


3 Answers

You need to split each argument into a separate element of a sequence.

Instead of this:

val cmd = Seq("curl", "-L", "-X POST", "-H 'Content-Type: application/json'", "-d " + jsonHash,  args.chronosHost + "/scheduler/" + jobType)

you need to write this:

val cmd = Seq("curl", "-L", "-X", "POST", "-H", "'Content-Type: application/json'", "-d " + jsonHash,  args.chronosHost + "/scheduler/" + jobType)

It puts each element of a sequence as an argument on a command line. So "-H 'Content-Type... looks like a single argument to curl while it should be 2.

Here is a simple way to test:

import scala.sys.process._
val cmd = Seq("find", "/dev/null", "-name", "null") // works
// does not work: val cmd = Seq("find", "/dev/null", "-name null")
val res = cmd.!!
println(res)
like image 64
yǝsʞǝla Avatar answered Sep 21 '22 12:09

yǝsʞǝla


Most of the other answers are a bit faffy, use the following trick to get Bash to do all the quote handling etc etc for you

import scala.sys.process._

Seq("bash", "-c", bashLine) !

For easier Googling myself: bash execute process sys.process pipe string scala

As a String pimp method (easy copy pasting)

import scala.sys.process._

implicit class PimpedString(bashLine: String) {
  def !!!: Int = Seq("bash", "-c", bashLine) !
}
like image 34
samthebest Avatar answered Sep 21 '22 12:09

samthebest


I also had a hard time to make this work. Enlighten by Aleksey, below worked for me. Note that, surprisingly, there is no extra quote (or double quote) for Content-type:

val deploy = Seq("curl", "-X", "POST", s"$ip/v2/apps", "-H", "Content-Type: application/json", "-d", s"@$containerJson")
println(deploy.!!) 
like image 21
jiangok Avatar answered Sep 19 '22 12:09

jiangok