6

I need to run a shell command from a Scala script and I use the following snippet for that:

import scala.sys.process.{Process, ProcessIO}

val command = "ls /tmp"
val process = Process(command)

val processIO = new ProcessIO(_ => (),
    stdout => scala.io.Source.fromInputStream(stdout).getLines.foreach(println),
    _ => ())
process.run(processIO)

The code works fine. I'm wondering why I get

java.io.IOException: Cannot run program "cd": error=2, No such file or directory

as soon as I change the command to cd /tmp && ls which is IMO equivalent to ls /tmp?

nab
  • 4,751
  • 4
  • 31
  • 42

2 Answers2

9

From Wikipedia on cd command:

[...] on Unix systems cd calls the chdir() POSIX C function. This means that when the command is executed, no new process is created to migrate to the other directory as is the case with other commands such as ls. Instead, the shell itself executes this command.

There is even a quote about Java there:

[...] neither the Java programming language nor the Java Virtual Machine supports chdir() directly; a change request remained open for over a decade while the team responsible for Java considered the alternatives, though by 2008 the request was denied after only limited support was introduced [...]

Try it yourself:

$ which ls
/bin/ls
$ which cd
$

In simple words, cd is not a program (process) you can run (like /bin/ls) - it is more of a command line directive.

What do you want to achieve? Changing the current working directory in Java? or change the working directory of the process you just created?

Community
  • 1
  • 1
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 4
    using `type cd` and `type ls` in the shell are also demonstrative in your shell. It should report that cd is not an executable, but a shell built-in – stew May 15 '12 at 18:52
  • Basicly I wanted to read an output of a certain command that should be run from a directory that is runtime known, like: `cd /somedir && find . -mindepth 5 -type d`. There's a number of ways to achieve it without `cd`, but having Perl background I was just curios why this was impossible to do with JVM. Thanks for the answer! – nab May 16 '12 at 12:48
0

Working solution:

import java.io.File
import scala.sys.process.{Process, ProcessIO}

object terminal_cd {
  def main(args: Array[String]): Unit = {
    val command = "ls"
    val process = Process(command, new File("/tmp"))

    val processIO = new ProcessIO(_ => (),
      stdout => scala.io.Source.fromInputStream(stdout).getLines.foreach(println),
      _ => ())
    process.run(processIO)
  }
}

All you need is to replace "cd /tmp" with java.io.File instance as a working dir parameter.

(The method to be called: /scala/src/library/scala/sys/process/Process.scala )

SergO
  • 2,703
  • 1
  • 30
  • 23