Come eseguire un comando shell in Java

1. Panoramica

Con questo tutorial illustreremo i due modi di eseguire un comando di shell dall'interno del codice Java .

Il primo è usare la classe Runtime e chiamare il suo metodo exec .

Il secondo modo, più personalizzabile, sarà creare e utilizzare un'istanza di ProcessBuilder .

2. Dipendenza dal sistema operativo

Prima di creare un nuovo processo che esegua il nostro comando di shell, dobbiamo prima determinare il sistema operativo su cui è in esecuzione la nostra JVM .

Questo perché, su Windows , dobbiamo eseguire il nostro comando come argomento della shell cmd.exe e su tutti gli altri sistemi operativi possiamo emettere una shell standard, chiamata sh:

boolean isWindows = System.getProperty("os.name") .toLowerCase().startsWith("windows");

3. Ingresso e uscita

inoltreabbiamo bisogno di un modo per collegarci ai flussi di input e output del nostro processo.

Almeno l'output deve essere consumato , altrimenti il ​​nostro processo non viene restituito correttamente, invece si bloccherà.

Implementiamo una classe comunemente usata chiamata StreamGobbler che consuma un InputStream :

private static class StreamGobbler implements Runnable { private InputStream inputStream; private Consumer consumer; public StreamGobbler(InputStream inputStream, Consumer consumer) { this.inputStream = inputStream; this.consumer = consumer; } @Override public void run() { new BufferedReader(new InputStreamReader(inputStream)).lines() .forEach(consumer); } }

NOTA: questa classe implementa l' interfaccia Runnable , il che significa che può essere eseguita da qualsiasi Executor .

4. Runtime.exec ()

Una chiamata al metodo a Runtime.exec () è un modo semplice, non ancora personalizzabile, per generare un nuovo sottoprocesso.

Nell'esempio seguente richiederemo un elenco di directory di una directory home di utenti e lo stamperemo sulla console:

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;

5. ProcessBuilder

Per la seconda implementazione del nostro problema informatico, utilizzeremo un ProcessBuilder . Questo è preferibile rispetto all'approccio Runtime perché siamo in grado di personalizzare alcuni dettagli.

Ad esempio siamo in grado di:

  • cambiare la directory di lavoro in cui è in esecuzione il nostro comando shell usando builder.directory ()
  • impostare una mappa valore-chiave personalizzata come ambiente utilizzando builder.environment ()
  • reindirizza i flussi di input e output a sostituzioni personalizzate
  • ereditarli entrambi sui flussi del processo JVM corrente utilizzando builder.inheritIO ()
ProcessBuilder builder = new ProcessBuilder(); if (isWindows) { builder.command("cmd.exe", "/c", "dir"); } else { builder.command("sh", "-c", "ls"); } builder.directory(new File(System.getProperty("user.home"))); Process process = builder.start(); StreamGobbler streamGobbler = new StreamGobbler(process.getInputStream(), System.out::println); Executors.newSingleThreadExecutor().submit(streamGobbler); int exitCode = process.waitFor(); assert exitCode == 0;

6. Conclusione

Come abbiamo visto in questo breve tutorial, possiamo eseguire un comando di shell in Java in due modi distinti.

In generale, se hai intenzione di personalizzare l'esecuzione del processo generato, ad esempio, per cambiare la sua directory di lavoro, dovresti considerare l'utilizzo di un ProcessBuilder .

Come sempre, troverai i sorgenti su GitHub .