How to Run a Shell Command in Java

Overview

Ezzel a bemutatóval a Java kódból egy Shell parancs futtatásának két módját mutatjuk be.

Az első a Runtime osztály használata és az exec metódus meghívása.

A második és jobban testre szabható mód egy ProcessBuilder példány létrehozása és használata lesz.

Operációs rendszerfüggőség

Mielőtt létrehoznánk egy új Processet, amely végrehajtja a shell parancsunkat, először meg kell határoznunk, hogy milyen operációs rendszeren fut a JVM-ünk.

Ez azért van, mert Windowson a parancsunkat a cmd argumentumaként kell futtatnunk.exe héjhoz, az összes többi operációs rendszeren pedig egy sh nevű szabványos héjprogramot adhatunk ki:

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

Bemenet és kimenet

Meg kell találnunk továbbá a módját, hogy bekapcsolódjunk a folyamatunk bemeneti és kimeneti adatfolyamába.

Mindenképpen a kimenetet kell fogyasztani – különben a folyamatunk nem tér vissza sikeresen, hanem lógni fog.

Implementáljuk a StreamGobbler nevű, gyakran használt osztályt, amely egy InputStream-et fogyaszt:

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

Figyelem: Ez az osztály a Runnable interfészt implementálja, ami azt jelenti, hogy bármilyen Executorral futtatható.

Runtime.exec()

A Runtime.exec() metódus meghívása egy egyszerű, még nem testreszabható módja egy új alfolyamat indításának.

A következő példában egy felhasználó home-könyvtárának könyvtárlistáját fogjuk lekérni és a konzolra kiírni:

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

Számítási problémánk második megvalósításához egy ProcessBuildert fogunk használni. Ezt előnyben részesítjük a Runtime megközelítéssel szemben, mert néhány részletet testre tudunk szabni.

Például képesek vagyunk:

  • megváltoztatni a munkakönyvtárat, amelyben a shell parancsunk fut a builder segítségével.directory()
  • beállítani egy egyéni kulcs-érték térképet környezetként a builder.environment() használatával
  • átirányítani a bemeneti és kimeneti folyamokat egyéni helyettesítésekre
  • megörökíteni mindkettőt az aktuális JVM folyamat folyamaira a 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;

Következtetés

Mint ebben a gyors bemutatóban láttuk, egy shell parancsot Java-ban két különböző módon tudunk végrehajtani.

Általában, ha azt tervezzük, hogy testre szabjuk az indított folyamat végrehajtását, például megváltoztatjuk a munkakönyvtárát, akkor érdemes egy ProcessBuilder használatát megfontolni.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.