0

I would like to be able to spawn an external process from Java, and periodically write to its input and read the response as if it were the console. Much of the time, however, when I read the process' output, nothing is available. Is there a good practice to do this sort of thing (even avoiding it)?

Here's a stripped down example of what doesn't work:

import org.apache.commons.exec.*;
import java.io.*;
//...
CommandLine cl = CommandLine.parse("/usr/bin/awk {print($1-1)}");
System.out.println(cl.toStrings());
Process proc = new ProcessBuilder(cl.toStrings()).start();
OutputStream os = proc.getOutputStream(); // avoiding *Buffered* classes
InputStream is = proc.getInputStream();   // to lessen buffering complications
os.write(("4" + System.getProperty("line.separator")).getBytes());
os.flush(); // Doesn't seem to flush.
// os.close(); // uncommenting works, but I'd like to keep the process running
System.out.println("reading");
System.out.println(is.read()); // read even one byte? usually is.available() -> 0

Strangely, if I wrap up the OutputStream in a BufferedWriter, the I can read from some processes (cat), but not others (awk, grep).

jlb
  • 679
  • 1
  • 10
  • 21
  • check my answer here if it helps, http://stackoverflow.com/questions/13008526/runtime-getruntime-execcmd-hanging/13008847#13008847 – Arham Oct 31 '12 at 14:52
  • Thanks, Arham. I hadn't considered that stdErr might fill up and removing synchronization issues is a nice way to go. Reading from stdErr in a separate thread doesn't help here, though. I'd like to be able to push data to the process, let the process work-- for example process the line or wait for any response, before moving on, like running from a shell. Should I just wrap up my external process with bash -c "..."? – jlb Oct 31 '12 at 15:47
  • I haven't tried running unix processes but windows processes in java, you'll have to try that out. But as I understand you want to control the exit of your application by yourself and not by the system. For that you can always put proc.destroy() inside a customized condition..?? – Arham Oct 31 '12 at 15:58
  • Either os.close() and proc.destroy() are fine. My problem is pushing output contents through the process' output, when available, can be read prior to calling close() or destroy(). (bash -c was a bust.) [link](http://stackoverflow.com/questions/10546122/java-exec-output-of-interactive-process-is-held-till-process-has-terminated) has a negative conclusion for a similar problem. Also for a generic process, it's not defined when the external process has finished processing the input, so using Arham's threading suggestion will probably yield a cleaner solution. – jlb Nov 03 '12 at 21:49
  • don't forget to upvote my answer from the link!! :) – Arham Nov 04 '12 at 05:37

1 Answers1

1

Generally, the approach taken is proper. Few things though:

  1. InputStream.read() is a blocking method. It waits for input and is not CPU-intensive. You should revolve around it...
  2. More than one byte can be read, just use read(byte[] buffer, int offset, int len)
  3. Wrapping input streams to BufferedInputStream eases the access (readLine() method). This is an alternative to BufferedReader.
  4. Don't forget to use Process.waitFor().

Also, make sure that the external process writes to standard output (and not to standard error). Two possibilities here:

  1. use Process.getErrorStream() (and treat it as another InputStream)
  2. change command line to /usr/bin/awk {print($1-1)} 2>&1. This will redirect standard error to standard output.
madman_xxx
  • 104
  • 8
  • Thanks, user999441. Process.waitFor() blocks until the completion of the external process. I'd like to keep the process running and read from its output prior to its termination. – jlb Oct 31 '12 at 15:25
  • The process won't finish until you kill it, either by literally killing, or by sending EOF (Ctrl + D). Or Ctrl + C. Also, running a process with a file as input and output might be a better idea - process has input in file, does the job, writes it to file, finishes and then Java processes the output file. – madman_xxx Oct 31 '12 at 15:53