Open jroper opened 5 years ago
does https://lihaoyi.github.io/Ammonite/#Ammonite-Shell offer anything here?
scala.sys.process
is pretty neglected these days
Probably, but I don't really want a shell. scala.sys.process
is used heavily by sbt and its plugins, along with in an ad-hoc manner by sbt users in their build files.
how about sth like this:
implicit final class StringContextExt(peer:StringContext) {
def stream(args:Any*):InputStream = new java.io.ByteArrayInputStream(peer.s(args:_*).getBytes("UTF-8"))
}
@SethTisue You mean PRs about scala.sys.process
are neglected. https://github.com/scala/scala/pull/8269 It would be less neglected as the promised module.
The current unDSL (and somehow I thought it would be easier):
scala> import scala.sys.process._
import scala.sys.process._
scala> def text: java.io.OutputStream => Unit = { out => out.write("hello, world".getBytes) ; out.close() }
text: java.io.OutputStream => Unit
scala> "head -10" run BasicIO.standard(text) // doesn't use ThreadProcess and PipedProcess
hello, worldres0: scala.sys.process.Process = scala.sys.process.ProcessImpl$SimpleProcess@47044f7d
scala> "head -10".#<<("mytext") // would be nice, #<< is currently for redirect to file
^
error: value #<< is not a member of String
scala> new java.io.File("foo.out") #<< new java.io.ByteArrayInputStream("hello".getBytes)
res11: scala.sys.process.ProcessBuilder = ( <input stream> #| /home/amarki/snips/foo.out )
scala> .!
res12: Int = 0
scala> "head -10" ! BasicIO.standard(text) // should already work, it's defined for ProcessBuilderImpl but not ProcessBuilder
^
error: type mismatch;
found : scala.sys.process.ProcessIO
required: scala.sys.process.ProcessLogger
I like echo
, but I also like the idea of leveraging "just read the string without more threads".
The current DSL has !
for exit value, !!
for stdout.toString. Optionally add <
to mean read stdin. Optionally provide a ProcessLogger
to process stdout/stderr.
So one proposal would be "add <<
to mean read from string". It would be slightly awkward with a logger: "head -10" !!<< ("some long input", ProcessLogger(err => println(err)))
.
I guess it kind of works:
scala> import scala.sys.process._
import scala.sys.process._
scala> "head -10" !<< "text"
textres0: Int = 0
scala> "head -10" !!<< "text"
res1: String =
"text
"
scala> "head -10" !!<< ("text", ProcessLogger(err => println(s"darn, $err")))
res2: String =
"text
"
scala> "head -10" !!<< """Now is the time
| for all do-gooders
| to do Some(good)."""
res3: String =
"Now is the time
for all do-gooders
to do Some(good).
"
scala> "head -10" #> new java.io.File("junk.out") !<< "hello, world"
res4: Int = 0
Or same as echo
, first-class process:
scala> "head -2" #<< "hello"
res0: scala.sys.process.ProcessBuilder = ( <here hello> #| [head, -2] )
scala> .!!
res1: String =
"hello
"
scala> "head -2" #<< """goodbye
| cruel
| world"""
res2: scala.sys.process.ProcessBuilder = ( <here goodb...> #| [head, -2] )
scala> .!!
res3: String =
"goodbye
cruel
"
To go full-on Mark Harrah.
Here's my exact use case, I want to write the Scala version of this shell script:
Naively I thought this might work:
But of course it doesn't work because
String
is executed as a command, not used as the source of input, so the error you get isCannot run program "FROM"
. This works:But is not very nice from a DSL perspective. There should be a straight forward way to pass a String as the input of a command. Here are some examples of potential APIs that could work:
Similar APIs could be supplied for byte arrays.