Read from the InputStream. You can append the output to a StringBuilder:

BufferedReader reader = 
                new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ( (line = reader.readLine()) != null) {
   builder.append(line);
   builder.append(System.getProperty("line.separator"));
}
String result = builder.toString();
Answer from Reimeus on Stack Overflow
🌐
Leo3418
leo3418.github.io › 2021 › 06 › 20 › java-processbuilder-stdout.html
Properly Handling Process Output When Using Java’s ProcessBuilder - Leo3418's Personal Site
Although this could solve the issue, it would significantly alter the behavior of java-ebuilder because originally java-ebuilder would not print Maven’s output to standard output. Redirect Maven’s output to /dev/null, which simulates the common practice of discarding a program’s output on Unix with a command such as mvn help:effective-pom > /dev/null. This can be done with the ProcessBuilder.redirectOutput method:
🌐
Baeldung
baeldung.com › home › java › core java › guide to java.lang.processbuilder api
Guide to java.lang.ProcessBuilder API | Baeldung
November 26, 2025 - We deliberately don’t call process.waitFor() until after we’ve read the output because the output buffer might stall the process · We’ve made the assumption that the java command is available via the PATH variable · In this next example, we’re going to see how to modify the working environment. But before we do that let’s begin by taking a look at the kind of information we can find in the default environment: ProcessBuilder processBuilder = new ProcessBuilder(); Map<String, String> environment = processBuilder.environment(); environment.forEach((key, value) -> System.out.println(key + value));
🌐
ZetCode
zetcode.com › java › processbuilder
Java ProcessBuilder - creating processes in Java
May 1, 2025 - The following example executes a command and shows its output. ... import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; void main() throws IOException { var processBuilder = new ProcessBuilder(); processBuilder.command("cal", "2022", "-m 2"); var process = processBuilder.start(); try (var reader = new BufferedReader( new InputStreamReader(process.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } }
🌐
CloudCompare
cloudcompare.org › cloudcompare website › board index › developers › mac os related topics
Grab command line mode output with Java ProcessBuilder - CloudCompare forum
February 28, 2021 - I'm not sure if the silent commands gets redirected on Mac to the standard console, you could run the same command in a terminal to see if it does. ... open -a CloudCompare.app --args -NO_TIMESTAMP -C_EXPORT_FMT LAS -O /Users/s/cc/pcl_1.las -O /Users/s/cc/pcl_2.las -MERGE_CLOUDS It opens the Command Line Mode Window, like the Java approach. An additional "-SILENT" let the app run in the background, (I can see the merged point cloud), but no output to the console.
Top answer
1 of 2
4

You don't want that call to waitFor() since it waits until the process is destroyed. You also don't want to read for as long as the InputStream is open, since such a read would terminate only when the process is killed.

Instead, you can simply start the process, and then wait for 7 seconds. Once 7 seconds have passed, read the available data in the buffer without waiting for the stream to close:

CopyBufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
Thread.sleep(7000); //Sleep for 7 seconds
while (stdInput.ready()) { //While there's something in the buffer
     //read & print - replace with a buffered read (into an array) if the output doesn't contain CR/LF
    System.out.println(stdInput.readLine()); 
}
p.destroy(); //The buffer is now empty, kill the process.

If the process keeps printing, so stdInput.ready() always returns true you can try something like this:

CopyBufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
char[] buffer = new char[16 * 1024]; // 16 KiB buffer, change size if needed
long startedReadingAt = System.currentTimeMillis(); //When did we start reading?
while (System.currentTimeMillis() - startedReadingAt < 7000) { //While we're waiting
    if (stdInput.ready()){
        int charsRead = stdInput.read(buffer); //read into the buffer - don't use readLine() so we don't wait for a CR/LF
        System.out.println(new String(buffer, 0, charsRead));  //print the content we've read
    } else {
        Thread.sleep(100); // Wait for a while before we try again
    }
}
p.destroy(); //Kill the process

In this solution, instead of sleeping, the thread spends the next 7 seconds reading from the InputStream, then it closes the process.

2 of 2
0

java.io.IOException: Stream closed That is probably because you're calling temp.readLine() after p.destroy().

The problem seems to be that the process doesn't add a new line termination after the part that you want to retrieve. To fix that, you can read the output from the program in small chunks instead of line by line.

Here is an example:

Copytry(InputStream is = p.getInputStream()){
    byte[] buffer = new byte[10];
    String content = "";
    for(int r = 0; (r = is.read(buffer))!=-1;){
        content+=new String(buffer, 0, r);
        if(content.equals("all content")){// check if all the necessary data was retrieved.
            p.destroy();
            break;
        }
    }
}catch(Exception e){
    e.printStackTrace();
}

If you know the exact format of the program's output, a better solution will be to use a scanner.

Copytry(Scanner sc = new Scanner(p.getInputStream())){
    while(sc.hasNext()){
        String word = sc.next();
    }
}catch(Exception e){
    e.printStackTrace();
}

The example above will read the program's output one word at a time.

From your comments it seems that the problem is that the process never terminates by itself and your program never exits the while loop.

To fix that, you can use a timer to destroy the process after a period of time, here is an example:

CopyTimer t = new Timer();
t.schedule(new TimerTask() {
    @Override
    public void run() {
        p.destroy();
        t.cancel();
        t.purge();
    }
}, 7000);

try(BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));){
    while ((inputRead=stdInput.readLine()) != null){
        ...
    }
}catch(Exception e){
    e.printStackTrace();
}

Keep in mind that this approach will always cause stdInput.readLine() to throw an exception.

🌐
Stack Overflow
stackoverflow.com › questions › 22803977 › retrieve-output-of-processbuilder
java - Retrieve output of ProcessBuilder - Stack Overflow
April 2, 2014 - Start a chat to get instant answers from across the network. Sign up to save and share your chats. Find centralized, trusted content and collaborate around the technologies you use most. Learn more about Collectives ... Bring the best of human thought and AI automation together at your work. Explore Stack Internal ... public String runCommand(parameters, boolean interactive) { Process p = null; // some code try { final ProcessBuilder pb = new ProcessBuilder(my_command); pb.inheritIO(); // So the output is displayed on the console p = pb.start(); p.waitFor(); } catch( IOException | InterruptedException e ) { e.printStackTrace(); } if (interactive ) { return p.exitValue() + ""; } else { // return the stdout of the process p } }
Find elsewhere
🌐
Alvin Alexander
alvinalexander.com › java › java-exec-processbuilder-process-2
Java exec - execute system processes with Java ProcessBuilder and Process (part 2) | alvinalexander.com
June 4, 2016 - public int executeCommand() throws IOException, InterruptedException { int exitValue = -99; try { // create the ProcessBuilder and Process ProcessBuilder pb = new ProcessBuilder(commandInformation); Process process = pb.start(); // you need this if you're going to write something to the command's input stream // (such as when invoking the 'sudo' command, and it prompts you for a password). OutputStream stdOutput = process.getOutputStream(); // i'm currently doing these on a separate line here in case i need to set them to null // to get the threads to stop. // see http://java.sun.com/j2se/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html InputStream inputStream = process.getInputStream(); InputStream errorStream = process.getErrorStream(); // these need to run as java threads to get the standard output and error from the command.
Top answer
1 of 12
188

Use ProcessBuilder.inheritIO, it sets the source and destination for subprocess standard I/O to be the same as those of the current Java process.

CopyProcess p = new ProcessBuilder().inheritIO().command("command1").start();

If Java 7 is not an option

Copypublic static void main(String[] args) throws Exception {
    Process p = Runtime.getRuntime().exec("cmd /c dir");
    inheritIO(p.getInputStream(), System.out);
    inheritIO(p.getErrorStream(), System.err);

}

private static void inheritIO(final InputStream src, final PrintStream dest) {
    new Thread(new Runnable() {
        public void run() {
            Scanner sc = new Scanner(src);
            while (sc.hasNextLine()) {
                dest.println(sc.nextLine());
            }
        }
    }).start();
}

Threads will die automatically when subprocess finishes, because src will EOF.

2 of 12
74

For Java 7 and later, see Evgeniy Dorofeev's answer.

For Java 6 and earlier, create and use a StreamGobbler:

CopyStreamGobbler errorGobbler = 
  new StreamGobbler(p.getErrorStream(), "ERROR");

// any output?
StreamGobbler outputGobbler = 
  new StreamGobbler(p.getInputStream(), "OUTPUT");

// start gobblers
outputGobbler.start();
errorGobbler.start();

...

Copyprivate class StreamGobbler extends Thread {
    InputStream is;
    String type;

    private StreamGobbler(InputStream is, String type) {
        this.is = is;
        this.type = type;
    }

    @Override
    public void run() {
        try {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null)
                System.out.println(type + "> " + line);
        }
        catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › lang › ProcessBuilder.html
ProcessBuilder (Java Platform SE 8 )
April 21, 2026 - The initial value is a copy of the environment of the current process (see System.getenv()). a working directory. The default value is the current working directory of the current process, usually the directory named by the system property user.dir. a source of standard input. By default, the subprocess reads input from a pipe. Java code can access this pipe via the output stream returned by Process.getOutputStream().
Top answer
1 of 1
3

For to be true, I tried your example and it outputs stream right away, but i didnt use text area for that, but console output. How exactly is your code invoked? Maybe it is related to GUI repaint manager - Is it invoked from EDT? If not, this may cause the delay.

Try to do something like this:

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            area.append(line);
        }
    });

As you are using background task (but you are not aware of that) you should use dedicated utility for this called SwingWorker https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html. As a bonus here is complete example you can run yourself. It uses swing worker to do a background job and updates GUI on EDT

public class LetsPing {

public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new BorderLayout());
    frame.setSize(300, 300);
    frame.setLocationRelativeTo(null);

    JTextArea textArea = new JTextArea();
    frame.add(textArea, BorderLayout.CENTER);
    frame.setVisible(true);

    new SwingWorker<Void, String>() {
        @Override
        protected Void doInBackground() throws Exception {
            ProcessBuilder pb = new ProcessBuilder().command("C:\\Windows\\SysWOW64\\PING.EXE", "127.0.0.1");
            pb.redirectErrorStream(true);
            Process process;
            process = pb.start();
            InputStream processStdOutput = process.getInputStream();
            Reader r = new InputStreamReader(processStdOutput);
            BufferedReader br = new BufferedReader(r);
            String line;
            while ((line = br.readLine()) != null) {
                publish(line);
            }
            return null;
        }

        @Override
        protected void process(List<String> chunks) {
            for (String line : chunks) {
                textArea.append(line);
                textArea.append("\n");
            }
        }
    }.execute();
}
}
🌐
Coderanch
coderanch.com › t › 725153 › java › Java-process-builder-returning-correct
Java process builder not returning correct (or any) output (Java in General forum at Coderanch)
January 11, 2020 - Bod McLeon wrote:And the output - well - that's non-existent (there is none - nothing is written to the console). Most likely an exception is being thrown, and you are simply ignoring it. You should at least print the stack. I would also printout the exit value: Edit: updated code ... I merged your stuff with the following thread. I hope that is okay by you. ... I am trying to call a python script from Java. I am using ProcessBuilder ...
Top answer
1 of 2
1

Here is an opinion on how to capture the standard output of a system command process into a string container.

Adapted from the web:

try {
  ProcessBuilder pb = new ProcessBuilder("echo", "dummy io");
  final Process p=pb.start();
  BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream()));
  String line;
  StringBuilder sb = new StringBuilder();
  while((line=br.readLine())!=null) sb.append(line);
}

System.out.println(sb.toString());
2 of 2
0

In congruence with my original comment on what would be a good example of Basic I/O. I hacked out some code, with a few more features than basic.


Extras

  • An environment shell for variables and
  • A working directory

These features add "profile-style" execution to your System commands.


Foundational Work

Java Threading and Joining by Oracle.


Code

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by triston on 11/2/17.
 */

public class Commander {

  private Commander(){} // no construction

  public static class StreamHandler implements Runnable {

    Object source;
    Object destination;

    StreamHandler(Object source, Object oDestination) {
      this.source = source; this.destination = oDestination;
    }

    public void run() {
      if (source instanceof InputStream) {
        BufferedReader br = new BufferedReader(new InputStreamReader((InputStream) source));
        String line;
        try {
          while ((line = br.readLine()) != null) ((StringBuilder) destination).append(line + '\n');
        } catch (IOException oE) {
        }
      } else {
        PrintWriter pw = new PrintWriter((OutputStream)destination);
        pw.print((String)source);
        pw.flush(); pw.close();
      }
    }

    public static Thread read(InputStream source, StringBuilder dest) {
      Thread thread = new Thread(new StreamHandler(source, dest));
      (thread).start();
      return thread;
    }

    public static Thread write(String source, OutputStream dest) {
      Thread thread = new Thread(new StreamHandler(source, dest));
      (thread).start();
      return thread;
    }

  }

  static Map<String, String> environment = loadEnvironment();

  static String workingDirectory = ".";

  static Map<String, String> loadEnvironment() {
    ProcessBuilder x = new ProcessBuilder();
    return x.environment();
  }

  static public void resetEnvironment() {
    environment = loadEnvironment();
    workingDirectory = ".";
  }

  static public void loadEnvirons(HashMap input) {
    environment.putAll(input);
  }

  static public String getEnviron(String name) {
    return environment.get(name);
  }

  static public void setEnviron(String name, String value) {
    environment.put(name, value);
  }

  static public boolean clearEnviron(String name) {
    return environment.remove(name) != null;
  }

  static public boolean setWorkingDirectory(String path) {
    File test = new File(path);
    if (!test.isDirectory()) return false;
    workingDirectory = path;
    return true;
  }

  static public String getWorkingDirectory() {
    return workingDirectory;
  }

  static public class Command {

    ProcessBuilder processBuilder = new ProcessBuilder();
    Process process;

    public Command(String... parameters) {
      processBuilder.environment().putAll(environment);
      processBuilder.directory(new File(workingDirectory));
      processBuilder.command(parameters);
    }

    public int start(String input, StringBuilder output, StringBuilder error) throws IOException {

      // start the process
      process = processBuilder.start();

      // start the error reader
      Thread errorBranch = StreamHandler.read(process.getErrorStream(), error);

      // start the output reader
      Thread outputBranch = StreamHandler.read(process.getInputStream(), output);

      // start the input
      Thread inputBranch = StreamHandler.write(input, process.getOutputStream());

      int rValue = 254;
      try {
        inputBranch.join(); rValue--;
        outputBranch.join(); rValue--;
        errorBranch.join(); rValue--;
        return process.waitFor();
      } catch (InterruptedException oE) {
        oE.printStackTrace();
        return rValue;
      }

  }

}

Testing

@Test public void foo() {
  Command cmd = new Command("sh", "--");
  StringBuilder output = new StringBuilder();
  StringBuilder error = new StringBuilder();
  int pValue = 127;
  try {
    pValue = cmd.start("echo well done > /dev/stderr\n\necho oh, wow; false", output, error);
  } catch (IOException oE) {
  }
  System.out.println("output: "+output.toString());
  System.out.println("error: "+error.toString());
  System.out.println("\nExit code: "+pValue);
  System.exit(pValue);
}

Bring your own package and JUnit annotations. This sample code demonstrates return value, command input, command standard output, and command error output.

My original design, called for the main thread to perform the standard output processing.

Have a great day.

🌐
Oracle
docs.oracle.com › javase › 7 › docs › api › java › lang › ProcessBuilder.html
ProcessBuilder (Java Platform SE 7 )
The argument may be null -- this means to use the working directory of the current Java process, usually the directory named by the system property user.dir, as the working directory of the child process. ... Sets this process builder's standard input source. Subprocesses subsequently started by this object's start() method obtain their standard input from this source. If the source is Redirect.PIPE (the initial value), then the standard input of a subprocess can be written to using the output stream returned by Process.getOutputStream().
Top answer
1 of 2
2

The problem I see here is that you create a process running a shell (OK), get hold of the input and output streams of that process (OK), read a command from the file (OK) and feed it to the process (OK). Then you keep reading output lines, which succeeds while the the first Java program executes and produces output.

Then the

while ((output = processOutput.readLine()) != null) { ...

blocks as there is neither another line nor EOF.

You can fix this by spawning a thread to read and print processOutput.

Another option (which I'd very much prefer) is to create one process per command. As far as I can see you don't even need a shell: you could execute java SolveProblem ... right away. (Unices have been built for efficient subprocess creation, and don't think the shell does it differently, so there's no additional overhead to be afraid of.)

Just two hints for calling java without a shell: make sure to use the full path name and split the command line into tokens.

Edit And here it is, just using a String[] instead of your text file containing commands.

for( String cmd: new String[]{ "java Y aaa", "java Y bbb","java Y ccc" } ){
     String[] toks = cmd.split( "\\s" );
     ProcessBuilder builder = new ProcessBuilder( toks );
     Process p = builder.start();

     // get output from the process
     InputStream is = p.getInputStream();
     InputStreamReader isr = new InputStreamReader(is);
     BufferedReader processOutput = new BufferedReader(isr);

     InputStream errorStream = p.getErrorStream();
     InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
     BufferedReader processErrorOutput = new BufferedReader(inputStreamReader);
     System.out.println("Executing " + cmd);
     String output;
     while( processErrorOutput.ready() &&
        (output = processErrorOutput.readLine()) != null) {
     System.out.println(output);
     }
     while ((output = processOutput.readLine()) != null) {
     System.out.println(output);
     }
     processErrorOutput.close();
     processOutput.close();
}

Output (silly Y prints argument three times):

Executing java Y aaa
1aaa
2aaa
3aaa
Executing java Y bbb
1bbb
2bbb
3bbb
Executing java Y ccc
1ccc
2ccc
3ccc

Another Edit If a marker line is inserted into the process output and the read loop checks the lines for this marker, the program can be used as it is (except for some corrections for closing processInput):

processInput.write(command + "; echo xxxEOFxxx");
//...
while ((output = processOutput.readLine()) != null
       && ! "xxxEOFxxx".equals(output)) {
    System.out.println(output);
}

Although I dislike the use of "magic strings" in this way it may be permissible here as you know the set of output lines of program Solve.

2 of 2
0

And yet better is to run error and stream reading in separate threads in order to provide make program able to do something else, terminate process for instance