Hur man kör ett skalkommando i Java

Översikt

Med den här handledningen illustrerar vi de två sätten att köra ett skalkommando från Java-kod.

Det första är att använda Runtime-klassen och anropa dess exec-metod.

Det andra och mer anpassningsbara sättet är att skapa och använda en ProcessBuilder-instans.

Operativsystemberoende

För att skapa en ny Process som utför vårt skalkommando måste vi först bestämma vilket operativsystem vår JVM körs på.

Det beror på att på Windows måste vi köra vårt kommando som argument till cmd.exe-skalet och på alla andra operativsystem kan vi utfärda ett standardskal, kallat sh:

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

Input och Output

Därutöver behöver vi ett sätt att koppla in oss på in- och outputströmmarna i vår process.

Minst utdata måste konsumeras – annars återvänder vår process inte framgångsrikt, utan hänger sig.

Låt oss implementera en vanligt förekommande klass som heter StreamGobbler som konsumerar en 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); }}

NOTAT: Den här klassen implementerar gränssnittet Runnable, vilket innebär att den kan exekveras av vilken Executor som helst.

Runtime.exec()

Ett metodanrop till Runtime.exec() är ett enkelt, ännu inte anpassningsbart, sätt att starta en ny underprocess.

I följande exempel begär vi en kataloglista över en användares hemkatalog och skriver ut den till konsolen:

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

För den andra implementationen av vårt beräkningsproblem kommer vi att använda en ProcessBuilder. Detta är att föredra framför Runtime-metoden eftersom vi kan anpassa vissa detaljer.

Till exempel kan vi:

  • ändra arbetskatalogen som vårt skalkommando körs i med hjälp av builder.directory()
  • upprätta en anpassad nyckelvärdeskarta som miljö med hjälp av builder.environment()
  • omdirigera inmatnings- och utdataströmmar till anpassade ersättningar
  • förälta dem båda till strömmarna i den aktuella JVM-processen med hjälp av 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;

Slutsats

Som vi har sett i den här snabba handledningen kan vi utföra ett skalkommando i Java på två olika sätt.

Generellt sett bör du överväga att använda en ProcessBuilder om du planerar att anpassa exekveringen av den spawnade processen, till exempel för att ändra dess arbetskatalog.

Lämna ett svar

Din e-postadress kommer inte publiceras.