Jak spustit příkaz shellu v Javě

Přehled

V tomto tutoriálu si ukážeme dva způsoby, jak spustit příkaz shellu z kódu Javy.

Prvním je použití třídy Runtime a zavolání její metody exec.

Druhým a přizpůsobitelnějším způsobem bude vytvoření a použití instance ProcessBuilder.

Závislost na operačním systému

Předtím, než vytvoříme nový Proces vykonávající náš příkaz shellu, musíme nejprve určit operační systém, na kterém běží naše JVM.

To proto, že ve Windows potřebujeme spustit náš příkaz jako argument příkazu cmd.exe a na všech ostatních operačních systémech můžeme vydat standardní příkaz shellu, který se nazývá sh:

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

Vstup a výstup

Dále potřebujeme způsob, jak se připojit ke vstupnímu a výstupnímu proudu našeho procesu.

Přinejmenším výstup musí být konzumován – jinak se náš proces úspěšně nevrátí, místo toho zůstane viset.

Implementujme běžně používanou třídu StreamGobbler, která konzumuje InputStream:

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); }}

Poznámka: Tato třída implementuje rozhraní Runnable, což znamená, že by ji mohl spustit libovolný Executor.

Runtime.exec()

Volání metody Runtime.exec() je jednoduchý, zatím nepřizpůsobitelný způsob, jak spustit nový podproces.

V následujícím příkladu si vyžádáme seznam adresářů domovského adresáře uživatele a jeho vypsání na konzoli:

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;

ProcessBuilder

Pro druhou implementaci našeho výpočetního problému budeme používat ProcessBuilder. Tomuto přístupu dáváme přednost před přístupem Runtime, protože jsme schopni přizpůsobit některé detaily.

Například jsme schopni:

  • změnit pracovní adresář, ve kterém se spouští náš příkaz shellu, pomocí builderu.directory()
  • nastavit vlastní mapu klíč-hodnota jako prostředí pomocí builder.environment()
  • přesměrovat vstupní a výstupní proudy na vlastní náhrady
  • přesměrovat oba proudy na proudy aktuálního procesu JVM pomocí 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;

Závěr

Jak jsme viděli v tomto stručném návodu, můžeme příkaz shellu v Javě spustit dvěma různými způsoby.

Všeobecně platí, že pokud plánujete přizpůsobit spouštění spuštěného procesu, například změnit jeho pracovní adresář, měli byste zvážit použití ProcessBuilder.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.