Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute external program from Java

I am trying to execute a program from the Java code. Here is my code:

public static void main(String argv[]) {
    try {
      String line;
      Process p = Runtime.getRuntime().exec(
          "/bin/bash -c ls > OutputFileNames.txt");
      BufferedReader input = new BufferedReader(
          new InputStreamReader(p.getInputStream()));
      while ((line = input.readLine()) != null) {
        System.out.println(line);
      }
      input.close();
    } catch (Exception err) {
      err.printStackTrace();
    }
}

My OS is Mac OS X 10.6.

If I remove the "> OutputFileNames.txt" from the getRuntime().exec() method, all the file names are printed on the console just fine. But I need it to be printed to a file.

Also, if I change the command to:

Process p = Runtime.getRuntime().exec(
    "cmd \c dir > OutputFileNames.txt"); 

and run it on Windows, it runs and prints the results in the file perfectly fine too.

I have read the other posts for executing another application from Java but none seemed to relate to my problem.

I would really appreciate any help I can get.

Thanks,

like image 900
Saurabh Lalwani Avatar asked May 20 '10 14:05

Saurabh Lalwani


3 Answers

To get the redirection to work as written, you need to do this:

Process p = Runtime.getRuntime().exec(
      new String[]{"/bin/bash", "-c", "ls > OutputFileNames.txt"});

The problem you were running into is the simple-minded way that that Runtime.exec(String) splits a command line into arguments.

If you were to run that command (as is) at a shell prompt, you would have had to have entered it as:

$ /bin/bash -c "ls > OutputFileNames.txt"

because the "-c" option for "bash" requires the command line for the spawned shell as a single shell argument. But if you were to put the naked quotes into the Java String, the Runtime.exec(String) method still get the splitting wrong. The only solution is to provide the command arguments as an array.

like image 52
Stephen C Avatar answered Nov 20 '22 01:11

Stephen C


A couple of things to look at.

  • check which directory your program is running in (by running pwd the same way), then check to ensure you have permissions to write to that directory.
  • see if that file OutputFileNames.txt already exists (and check permissions).
  • if the file does exist, delete it and re-run to see if it gets re-created, and look at the contents if it does.
  • try using the command "/bin/bash -c 'ls > OutputFileNames.txt'" - it may be that the bash output is not the same as the ls output (in your example the redirection could be applying to bash rather than ls).
like image 1
paxdiablo Avatar answered Nov 20 '22 03:11

paxdiablo


The problem is happening because standard output of the process is being directed to the file, so the java Process cannot collect the output.

If you want the output written to a file, and be available for reading in java, then you have two options:

  1. Keep the redirect in place, and then read the listing from the OutputFile.txt in java, e.g. using new FileReader("OutputFile.txt"). Note that exec() is asynchronous, and can return before the process has finished writing to file, so you will need to wait for the Process to exit, by using Process.waitFor().
  2. Remove the redirect, and read the listing directly into java (as you are doing.) You can then write this listing out to a file using FileWriter.

The bottom line is that you can't use both redirect and read the output from the Process at the same time - it's one or the other.

EDIT: Your comments indicate that 1) is the preferred approach. This will write the output to a file (using the OS shell) which you then read in from java when the process exits.

like image 1
mdma Avatar answered Nov 20 '22 01:11

mdma