0

Below is my code to read the output from console. I need to read the tracert path live to console.

Below code prints the data at once after finishing the process only.

Can someone help me?

ProcessBuilder f = new ProcessBuilder("cmd.exe","tracert ip_address");
Process p = f.start();

BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader readers = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String lines =null;
System.out.println();

while((lines = reader.readLine())!=null) {
    System.out.println("lines:"+lines);
}

String lines1 =null;
while((lines1 = readers.readLine())!=null) {
    System.out.println("error lines:"+lines1);
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • Maybe this could help you: https://thilosdevblog.wordpress.com/2021/10/21/how-to-handle-the-output-of-the-processbuilder/ – Thilo Schwarz Oct 21 '21 at 10:05
  • @Thilo Schwarz That example does not consume standard error stream on separate thread to standard input so ProcessBuilderWrapper will fail to work in circumstances where the error buffer fills with large content before the input buffer is read. For example compare ProcessBuilderWrapper in Windows with commands: `{"cmd.exe", "/c", "dir /s C:\\Windows\\System32 && echo Hello STDERR 1>&2"}` and `{"cmd.exe", "/c", "dir /s C:\\Windows\\System32 1>&2 && echo Hello STDOUT"}`. The second cmd stalls. – DuncG Oct 21 '21 at 15:08
  • @DuncG I've tested it with a separate script and it works as expected under ubuntu and macOS. I've updated my blog post. Whats the correct way to solve the buffer issue? I didn't get any stream before starting the process ... Is ``` #redirectErrorStream(true)``` really the only solution? – Thilo Schwarz Oct 21 '21 at 17:28
  • 1
    @Thilo Schwarz You should be able to reproduce on Linux (prob Mac similarly) with `{"/bin/bash", "-c", "ls -alrt /path/to/a/big/dir/tree 1>&2 && echo Hello STDOUT"}`. The three fixes I know work are one of `pb.redirectErrorStream(true)`, `pb.redirectError(File)` or set up a new thread/background task for the bit with `try (var stderr = pb.getErrorStream()) { stderr.transferTo(wherever); }` - (and await/join on task after waitFor) – DuncG Oct 21 '21 at 17:43
  • @DuncG Thanx a lot for your explanation. I'll rewrite my post! – Thilo Schwarz Oct 22 '21 at 08:01

1 Answers1

1

Here are some suggestions which should help.

You do not need to use CMD.EXE to launch TRACERT.EXE, as you can run it directly if it is on the path or fully qualify it's path. If you do use CMD then use "/C" flag to ensure it runs just that command.

String ip = "bbc.com";
String [] cmd = {"cmd.exe", "/c", "tracert "+ip};
System.out.println("Running:"+Arrays.toString(cmd));

Consuming STDOUT and STDERR in same thread can lead to the process freezing if it writes large amounts. Use files redirects, or redirect ERR->OUT:

ProcessBuilder f = new ProcessBuilder(cmd);
f.redirectErrorStream(true);
Process p = f.start();

Don't waste time with a loop over the output, send to a new ByteArrayOutputStream() if you want to capture it, or just to System.out:

try(var stdout = p.getInputStream()) {
   stdout.transferTo(System.out);
}

Always wait for the process to end:

int rc = p.waitFor();

System.out.println("Exit:"+p.pid()+" RESULT:"+rc +' '+(rc == 0 ? "OK":"**** ERROR ****"));
DuncG
  • 12,137
  • 2
  • 21
  • 33
  • Hi DuncG, I tried this way also but the data is printing AFTER completion of process p but I need data from runtime of Process to Console. Please help me if you know any way to do this. – Venkata Narayana Gorusetty Oct 18 '21 at 13:44
  • The System.out is before p.waitFor() so the output can't be after the process ends. Are you doing something not shown in this question? – DuncG Oct 18 '21 at 14:30