andreask
andreask

Reputation: 109

How to make shell command process finish?

I want to execute a specific shell command on a Linux machine with Java. So I found a tutorial by/from baeldung.com.

Link to the tutorial

My problem is that even the example command (process) never finishes.

private static class StreamGobbler implements Runnable {
    private InputStream inputStream;
    private Consumer<String> consumer;

    public StreamGobbler(InputStream inputStream, Consumer<String> consumer) {
        this.inputStream = inputStream;
        this.consumer = consumer;
    }

    @Override
    public void run() {
        new BufferedReader(new InputStreamReader(inputStream)).lines()
          .forEach(consumer);
    }
}

boolean isWindows = System.getProperty("os.name")
  .toLowerCase().startsWith("windows");
String homeDirectory = System.getProperty("user.home");
Process process;
if (isWindows) {
    process = Runtime.getRuntime()
      .exec(String.format("cmd.exe /c dir %s", homeDirectory));
} else {
    process = Runtime.getRuntime()
      .exec(String.format("sh -c ls %s", homeDirectory));
}
StreamGobbler streamGobbler = 
  new StreamGobbler(process.getInputStream(), System.out::println);
Executors.newSingleThreadExecutor().submit(streamGobbler);
int exitCode = process.waitFor();
assert exitCode == 0;

Hope that somebody has an idea.

Upvotes: 0

Views: 318

Answers (1)

Andreas
Andreas

Reputation: 159086

When you call Executors.newSingleThreadExecutor(), a background thread is started. Since the thread is not a daemon thread, the JVM will not terminate until the thread stops running. That never happens, so your Java program keeps running, even though the main thread has terminated.

There are multiple ways of fixing it:

  • Don't use an executor, just start a thread, which will end when the run() method of StreamGobbler ends.

    StreamGobbler streamGobbler = ...
    new Thread(streamGobbler).start();
    int exitCode = process.waitFor();
    
  • Shut down the executor when you're done with it.

    StreamGobbler streamGobbler = ...
    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.submit(streamGobbler);
    int exitCode = process.waitFor();
    executor.shutdown();
    

Upvotes: 4

Related Questions