tags:

views:

239

answers:

3

Hi, 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,

+1  A: 

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.

Stephen C
the javadoc states that the command line is split: "The command argument is parsed into tokens and then executed as a command in a separate process. The token parsing is done by a StringTokenizer...". See http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Runtime.html#exec%28java.lang.String%29 new StringTokenizer(command)
mdma
@mdma - and that of course is the problem. StringTokenizer does not understand quoted strings.
Stephen C
Ok, I see your edit, that you've quoted the command to bash. I didn't notice the original command line was wrong.
mdma
Thanks Stephen. That thing worked. I am sorry to ask a silly question but I am naive to developing in mac environment. Now, there is another problem I am having, The application I want to run on the terminal starts its own little program and prints to itself and probably not the terminal. Because I cannot read anything from the console when I execute it. But, when I actually go to terminal and run the program I can see the output there. So, what I am trying to do is spit all the output in a file and read that instead. But again, the file created by the java code is empty.
Saurabh Lalwani
@Saurabh please ask a separate Question. And please see if you can make it easier to understand.
Stephen C
@Saurabh Please see my answer. You cannot redirect to a file and read the process output from java at the same time.
mdma
@Stephen, here is the question again:http://stackoverflow.com/questions/2875085/execute-external-program-from-javaLet me know if it is still not clear.Thanks..
Saurabh Lalwani
+1  A: 

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).
paxdiablo
+1  A: 

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.

mdma