Javaでシェルコマンドを実行する方法

Javaでシェルコマンドを実行する方法

1. 概要

このチュートリアルでは、executing a shell command from within Java codeの2つの方法を説明します。

1つ目は、Runtimeクラスを使用して、そのexecメソッドを呼び出すことです。

2番目のよりカスタマイズ可能な方法は、ProcessBuilderインスタンスを作成して使用することです。

2. オペレーティングシステムの依存関係

シェルコマンドを実行する新しいProcessを作成する前に、まずJVMが実行されているオペレーティングシステムを特定する必要があります。

これは、Windowsでは、cmd.exeシェルへの引数としてコマンドを実行する必要があり、他のすべてのオペレーティングシステムでは、sh:と呼ばれる標準シェルを発行できるためです。

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

3. 入出力

さらに**プロセスの入力および出力ストリームにフックする方法が必要です。

少なくともthe output must be consumed –そうしないと、プロセスが正常に戻らず、代わりにハングします。

InputStreamを消費するStreamGobblerと呼ばれる一般的に使用されるクラスを実装しましょう。

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

NOTE:このクラスはRunnableインターフェースを実装しています。つまり、任意のExecutorで実行できます。

4. Runtime.exec()

Runtime.exec()へのメソッド呼び出しは、新しいサブプロセスを生成するための単純な、まだカスタマイズできない方法です。

次の例では、ユーザーのホームディレクトリのディレクトリリストを要求し、それをコンソールに出力します。

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

コンピューティング問題の2番目の実装では、ProcessBuilderを使用します。 一部の詳細をカスタマイズできるため、これはRuntimeアプローチよりも優先されます。

たとえば、次のことができます。

  • builder.directory()を使用して、シェルコマンドが実行されている作業ディレクトリを変更します

  • builder.environment()を使用して、環境としてカスタムKey-Valueマップを設定します

  • 入力および出力ストリームをカスタム置換にリダイレクトします

  • builder.inheritIO()を使用して、両方を現在のJVMプロセスのストリームに継承します

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. 結論

このクイックチュートリアルで見たように、2つの異なる方法でJavaでシェルコマンドを実行できます。

一般に、生成されたプロセスの実行をカスタマイズすることを計画している場合、たとえば、その作業ディレクトリを変更する場合は、ProcessBuilderの使用を検討する必要があります。

いつものように、ソースon GitHubが見つかります。