TheWolf
TheWolf

Reputation: 1695

Printing Runtime exec() OutputStream to console

I am trying to get the OutputStream of the Process initiated by exec() to the console. How can this be done?

Here is some incomplete code:

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;

public class RuntimeTests
{
    public static void main(String[] args)
    {
        File path = new File("C:\\Dir\\Dir2");
        String command = "cmd /c dir";
        Reader rdr = null;
        PrintStream prtStrm = System.out;
        try
        {
            Runtime terminal = Runtime.getRuntime();

            OutputStream rtm = terminal.exec(command, null, path).getOutputStream();
            prtStrm = new PrintStream(rtm);
            prtStrm.println();
        } 
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

Upvotes: 51

Views: 94168

Answers (7)

Eugene Kuleshov
Eugene Kuleshov

Reputation: 31795

See Benjamin Gruenbaum answer covering ProcessBuilder API available since Java 7.

You need to start a new thread that would read process output happening after Process.waitFor(). Then process output can be copied the console from that thread.

Process.getOutputStream() is actually the input, ie, stdin to the process. Process.getInputStream() and Process.getErrorStream() return InputStream objects which are the stdout and stderr of the process. The InputStreams and OutputStream are from the caller's perspective, which is the opposite of the process's perspective.

The process's output, stdout, is input to the caller, therefore the caller gets a getInputStream() and reads the stdout from it:

Process proc = Runtime.getRuntime().exec(cmdArr, env, cwdir);

InputStreamReader isr = new InputStreamReader(proc.getInputStream());
BufferedReader rdr = new BufferedReader(isr);
while((line = rdr.readLine()) != null) { 
  System.out.println(line);
} 

isr = new InputStreamReader(proc.getErrorStream());
rdr = new BufferedReader(isr);
while((line = rdr.readLine()) != null) { 
  System.out.println(line);
} 
rc = proc.waitFor();  // Wait for the process to complete

Process.getOutputStream() is used for the caller to 'output' data into the stdin of the process. This code could be added after 'proc' is created in the first line of the example above, to send data into stdin of the process:

// Send data to stdin of the process (in development, needs input content)
OutputStream os = proc.getOutputStream();
Bytes content = new Bytes("Hello\nasdf\n adma");
os.write(content.arr, content.off, content.length());
os.close(); // should use try/finally or try/resource

Do the above before reading the output. Remember to close the OutputStream os (either using try/resource or try/finally). So, the process knows that stdin is complete and it can finish processing the info.

Upvotes: 8

Benjamin Gruenbaum
Benjamin Gruenbaum

Reputation: 276536

I recently ran into this problem and just wanted to mention that since java 7 the process builder api has been expanded. This problem can now be solved with:

ProcessBuilder pb = new ProcessBuilder("yourcommand");
pb.redirectOutput(Redirect.INHERIT);
pb.redirectError(Redirect.INHERIT);
Process p = pb.start();

Upvotes: 118

Mohamed Anees A
Mohamed Anees A

Reputation: 4601

I know this is a very old question, but a better alternate for the above answers would be

ProcessBuilder builder = new ProcessBuilder(command);
builder.inheritIO();
Process p = builder.start();

From the docs of ProcessBuilder.inheritIO(),

Sets the source and destination for subprocess standard I/O to be the same as those of the current Java process.

Hope this helps someone!

Upvotes: 5

radiantRazor
radiantRazor

Reputation: 489

If you can use org.apache.commons.io.IOUTils from commons-io,

System.out.println(IOUtils.toString(process.getInputStream()));
System.err.println(IOUtils.toString(process.getErrorStream()));

Upvotes: 2

samaitra
samaitra

Reputation: 774

I faced the similar problem and I am using the following code.

Process p = Runtime.getRuntime().exec(".....");
p.waitFor();

String line;

BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while((line = error.readLine()) != null){
    System.out.println(line);
}
error.close();

BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((line=input.readLine()) != null){
    System.out.println(line);
}

input.close();

OutputStream outputStream = p.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.println();
printStream.flush();
printStream.close();

Upvotes: 13

yegor256
yegor256

Reputation: 105193

Try VerboseProcess from jcabi-log:

String output = new VerboseProcess(new ProcessBuilder("foo.bat")).stdout();

The class starts a background thread, listens to the output stream, and logs it.

Upvotes: 2

Stijn Geukens
Stijn Geukens

Reputation: 15628

I believe this is what you're looking for:

  String line;
  Process p = Runtime.getRuntime().exec(...);
  BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
  while ((line = input.readLine()) != null) {
    System.out.println(line);
  }
  input.close();

Upvotes: 46

Related Questions