How to Run a Shell Command in Java

Overview

Met deze tutorial zullen we de twee manieren illustreren om een shell commando uit te voeren vanuit Java code.

De eerste is om de Runtime class te gebruiken en zijn exec method aan te roepen.

De tweede en meer aanpasbare manier, zal zijn om een ProcessBuilder instantie te maken en te gebruiken.

Afhankelijkheid van het besturingssysteem

Voordat we een nieuw Process gaan maken dat ons shell commando uitvoert, moeten we eerst bepalen op welk besturingssysteem onze JVM draait.

Dat komt omdat we op Windows ons commando moeten uitvoeren als argument voor de cmd.exe shell en op alle andere besturingssystemen kunnen we een standaard shell uitvoeren, genaamd sh:

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

Input en output

Verder hebben we een manier nodig om in te haken op de input en output streams van ons proces.

Op zijn minst moet de uitvoer worden geconsumeerd – anders keert ons proces niet succesvol terug, maar blijft hangen.

Laten we een veelgebruikte class implementeren, StreamGobbler genaamd, die een InputStream consumeert:

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

NOOT: Deze class implementeert de Runnable interface, wat betekent dat hij door elke Executor kan worden uitgevoerd.

Runtime.exec()

Een methode-aanroep van Runtime.exec() is een eenvoudige, nog niet aan te passen, manier om een nieuw sub-proces te spawnen.

In het volgende voorbeeld vragen we een directory-lijst op van een gebruikers home-directory en printen die naar de 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;

ProcessBuilder

Voor de tweede implementatie van ons rekenprobleem, gebruiken we een ProcessBuilder. Dit heeft de voorkeur boven de Runtime aanpak, omdat we in staat zijn om een aantal details aan te passen.

Zo kunnen we bijvoorbeeld:

  • de werkdirectory veranderen waarin ons shell commando wordt uitgevoerd met builder.directory()
  • een aangepaste key-value map als omgeving instellen met builder.environment()
  • invoer- en uitvoerstromen omleiden naar aangepaste vervangingen
  • beiden overerven naar de streams van het huidige JVM-proces met 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;

Conclusie

Zoals we in deze korte tutorial hebben gezien, kunnen we een shell commando in Java op twee verschillende manieren uitvoeren.

In het algemeen, als je van plan bent om de uitvoering van het gespawnde proces aan te passen, bijvoorbeeld om zijn werkdirectory te veranderen, moet je overwegen om een ProcessBuilder te gebruiken.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.