Trouble invoking command with quoted string using Scala's sys.process API - scala

As can be seen in the following console session, the same command invoked from Scala produces different results than when run in the terminal.
~> scala
Welcome to Scala 2.12.6 (OpenJDK 64-Bit Server VM, Java 1.8.0_172).
Type in expressions for evaluation. Or try :help.
scala> import sys.process._
import sys.process._
scala> """emacsclient --eval '(+ 4 5)'""".!
*ERROR*: End of file during parsingres0: Int = 1
scala> :quit
~> emacsclient --eval '(+ 4 5)'
9
Has anyone encountered this issue and/or know of a work around?
I thought this may have been a library bug, so opened an issue as well: https://github.com/scala/bug/issues/10897

It seems that Scala's sys.process api doesn't support quoting. The following works: Seq("emacsclient", "--eval", "(+ 4 5)").!.

Related

Scala: run external script with dash multiple arguments

As reported here Execute external command
in order to run an external shell command or script in Scala the right code should be:
import scala.sys.process._
val cmd = "ls -l /home" // Your command
val output = cmd.!! // Captures the output
I've noticed this works for some commands but not for others like "java -version" (especially if they have dash "-" before arguments)
Is there a correct way to execute commands like "python --version" or a more complex python script like "python /path/to/my_script.py -x value -y value" ?
Seems to work with dashes
$ scala
Welcome to Scala 2.13.6 (Eclipse OpenJ9 VM, Java 1.8.0_292).
Type in expressions for evaluation. Or try :help.
scala> import scala.sys.process._
import scala.sys.process._
scala> "java -version".!!
openjdk version "1.8.0_292"
...
scala> "python3 --version".!!
val res1: String =
"Python 3.8.5
"

What is the equivalent to os.system in Scala?

I am writing a scala program in which I would to run a system command, reading the input from stdin, and writing it's output to stdout. (So, basically just like running the command in the shell."
In python, os.system("command") has this behavior. For instance, os.system("python") opens another Python REPL when run.
In Scala, running "python" !! seems to run the process and halt immediately. What is the easiest way to do the equivalent of os.system in Scala? I feel like this can probably be done with scala.sys.process.ProcessIO, but I haven't been able to find any clear examples anywhere of how this can be done.
As long as you don't need this to work in the Scala REPL, then !< should be all you need.
%> cat so.sc
import sys.process._
object Obj extends App {
Seq("python3","-i").!<
}
%> scalac so.sc
%> scala Obj
Python 3.6.8 (default, Aug 20 2019, 17:12:48)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 4
>>> print('x: ' + str(x))
x: 4
>>> <CTL-D>
%>
Python isn't being invoked in a terminal/TTY environment so the -i option is needed to force it into interactive mode.

Why does IntelliJ's scala console display question marks when I print greek characters?

For example, I observe the following behavior:
Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 12.0.1).
Type in expressions for evaluation. Or try :help.
scala> print("hi!")
hi!
scala> print("γεια!")
????!
How can I fix this?
when setting the file.encoding to UTF-8 I get:
scala> sys.props("file.encoding")
res0: String = UTF-8
scala> print("γεια!")
????!
scala>
The point is that run/debug console uses the IDEA encoding. IDEA is a java application and encoding can be set in the idea.exe.vmoptions file as ordinary VM parameter. This file lies near your IDEA executabe file and conteins a set of JVM parameters. Add -Dfile.encoding=UTF-8 there to set encoding in UTF-8.
coming from https://intellij-support.jetbrains.com/hc/en-us/community/posts/206290929-How-can-you-display-UTF-8-characters-in-the-Console-tab-
Check if the file.encoding is set to UTF-8 by running Scala Console and evaluate
sys.props("file.encoding")
If it does not return
res0: String = UTF-8
then stop and edit Scala Console run configuration. Under VM Options input field enter Unicode file encoding like so
-Dfile.encoding=UTF-8
Now rerun Scala Console run configuration, re-evaluate sys.props("file.encoding") to make sure it says UTF-8, and then try print("γεια!") which should now output
scala> print("γεια!")
γεια!

Use a variable in a shell command in a Scala program (not REPL)

Inside a program - not the REPL - is it possible to introduce a string variable to represent the shell command to be executed ?
import sys.process._
val npath = opath.substring(0,opath.lastIndexOf("/"))
s"rm -rf $npath/*" !
s"mv $tmpName/* $npath/" !
The compiler says:
:103: error: type mismatch;
found : String
required: scala.sys.process.ProcessLogger
s"mv $tmpName/* $npath/" !
^
Note that in the REPL this can be fixed by using
:power
But .. we're not in the REPL here.
I found a useful workaround that mostly preserves the intended structure:
Use the
Seq[String].!
syntax. But by using spaces as a delimiter we can still write it out in a kind of wysiwig way
import sys.process._
val npath = opath.substring(0,opath.lastIndexOf("/"))
s"rm -rf $npath/*".split(" ").toSeq.!
s"mv $tmpName/* $npath/".split(" ").toSeq.!
The limitation here is that embedded spaces in the command would not work - they would require an explicit Seq of each portion of the command.
Here is a bit nicer if there were a set of commands to run:
Seq(s"rm -rf $npath/*",s"mv $tmpName/* $npath/").foreach{ cmd=>
println(cmd)
cmd.split(" ").toSeq.!
}

How to start a Scala method from command line?

This question may sound a bit stupid, but I couldn't figure out, how to start a Scala method from the command line.
I compiled the following file Test.scala :
package example
object Test {
def print() {
println("Hello World")
}
}
with scalac Test.scala.
Then, I can run the method print with scala in two steps:
C:\Users\John\Scala\Examples>scala
Welcome to Scala version 2.9.2 (Java HotSpot(TM) Client VM, Java 1.6.0_32).
Type in expressions to have them evaluated.
Type :help for more information.
scala> example.Test.print
Hello World
But what I really like to do is, to run the method directly from the command line with one command like scala example.Test.print.
How can I achieve this goal ?
UPDATE:
Suggested solution by ArikG does not work for me - What I am missing ?
C:\Users\John\Scala\Examples>scala -e 'example.Test.print'
C:\Users\John\AppData\Local\Temp\scalacmd1874056752498579477.scala:1: error: u
nclosed character literal
'example.Test.print'
^
one error found
C:\Users\John\Scala\Examples>scala -e "example.Test.print"
C:\Users\John\AppData\Local\Temp\scalacmd1889443681948722298.scala:1: error: o
bject Test in package example cannot be accessed in package example
example.Test.print
^
one error found
where
C:\Users\John\Scala\Examples>dir example
Volume in drive C has no label.
Volume Serial Number is 4C49-8C7F
Directory of C:\Users\John\Scala\Examples\example
14.08.2012 12:14 <DIR> .
14.08.2012 12:14 <DIR> ..
14.08.2012 12:14 493 Test$.class
14.08.2012 12:14 530 Test.class
2 File(s) 1.023 bytes
2 Dir(s) 107.935.760.384 bytes free
UPDATE 2 - Possible SOLUTIONs:
As ArikG correctly suggested, with scala -e "import example.Test._; print" works well with Windows 7.
See answer of Daniel to get it work without the import statement
Let me expand on this solution a bit:
scala -e 'example.Test.print'
Instead, try:
scala -cp path-to-the-target-directory -e 'example.Test.print'
Where the target directory is the directory where scala used as destination for whatever it compiled. In your example, it is not C:\Users\John\Scala\Examples\example, but C:\Users\John\Scala\Examples. The directory example is where Scala will look for classes belonging to the package example.
This is why things did not work: it expected to find the package example under a directory example, but there were no such directory under the current directory in which you ran scala, and the classfiles that were present on the current directory were expected to be on the default package.
The best way to do this is to extend App which is a slightly special class (or at least DelayedInit which underlies it is):
package example
object Test extends App {
println("Hello World")
}
It's still possible to add methods to this as well, the body of the object is executed on startup.
Here you go:
scala -e 'example.Test.print'