Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the output from a process and set a timeout?

How can I obtain a process' output while setting a timeout value?

I am currently using Apache Commons IO utils to create a string from the process' standard and error outputs.

The code below, as is (with the comments), works fine for processes that terminate. However, if the process doesn't terminate, the main thread doesn't terminate either!

If I uncomment out the commented code and instead comment out process.waitfor(), the method will properly destroy non terminating processes. However, for terminating processes, the output isn't properly obtained. It appears that once waitFor is completed, I cannot get the process' input and error streams?

Finally, if I attempt to move the commented section to where process.waitFor() currently is, remove process.waitFor() and uncomment the commented section, then for non terminating processes, the main thread also won't stop. This is because the process.waitFor(15, ...) will never be reached.

private static Outputs runProcess(String command) throws Exception {
    Process process = Runtime.getRuntime().exec(command);

    // if (!process.waitFor(15, TimeUnit.SECONDS)) {
    // System.out.println("Destroy");
    // process.destroy();
    // }

    // Run and collect the results from the standard output and error output
    String stdStr = IOUtils.toString(process.getInputStream());
    String errStr = IOUtils.toString(process.getErrorStream());

    process.waitFor();

    return new Outputs(stdStr, errStr);
}
like image 927
waylonion Avatar asked Oct 18 '25 07:10

waylonion


1 Answers

As @EJP suggested, You can use different threads to capture the streams or use ProcessBuilder or redirect to a file from your command.
Here are 3 approaches that I feel you can use.

  1. Using different threads for Streams.

    Process process = Runtime.getRuntime().exec("cat ");
    
    ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
    
    Future<String> output = newFixedThreadPool.submit(() -> {
        return IOUtils.toString(process.getInputStream());
    });
    Future<String> error = newFixedThreadPool.submit(() -> {
        return IOUtils.toString(process.getErrorStream());
    });
    
    newFixedThreadPool.shutdown();
    
    // process.waitFor();
    if (!process.waitFor(3, TimeUnit.SECONDS)) {
        System.out.println("Destroy");
        process.destroy();
    }
    
    System.out.println(output.get());
    System.out.println(error.get());
    
  2. Using ProcessBuilder

    ProcessBuilder processBuilder = new ProcessBuilder("cat")
            .redirectError(new File("error"))
            .redirectOutput(new File("output"));
    
    Process process = processBuilder.start();
    
    // process.waitFor();
    if (!process.waitFor(3, TimeUnit.SECONDS)) {
        System.out.println("Destroy");
        process.destroy();
    }
    
    System.out.println(FileUtils.readFileToString(new File("output")));
    System.out.println(FileUtils.readFileToString(new File("error")));
    
  3. Use a redirection operator in your command to redirect Output & Error to a file and then Read from File.

Here is very good blog which explains different ways of handling Runtime.Exec

like image 54
Kishore Bandi Avatar answered Oct 19 '25 21:10

Kishore Bandi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!