Comment exécuter une commande shell en Java

Comment exécuter une commande shell en Java

1. Vue d'ensemble

Avec ce didacticiel, nous allons illustrer les deux méthodes deexecuting a shell command from within Java code.

La première consiste à utiliser la classeRuntime et à appeler sa méthodeexec.

Le deuxième moyen, plus personnalisable, sera de créer et d'utiliser une instanceProcessBuilder.

2. Dépendance du système d'exploitation

Avant de créer un nouveauProcess exécutant notre commande shell, nous devons d'abord déterminer le système d'exploitation sur lequel notreJVM est exécuté.

C'est parce que, surWindows, nous devons exécuter notre commande comme argument du shellcmd.exe et sur tous les autres systèmes d'exploitation, nous pouvons émettre un shell standard, appelésh:

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

3. Entrée et sortie

De plus **, nous avons besoin d’un moyen d’accrocher les flux d’entrée et de sortie de notre processus.

Au moinsthe output must be consumed - sinon notre processus ne retourne pas avec succès, il se bloquera à la place.

Implémentons une classe couramment utilisée appeléeStreamGobbler qui consomme unInputStream:

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: Cette classe implémente l'interfaceRunnable, ce qui signifie qu'elle pourrait être exécutée par n'importe quelExecutor.

4. Runtime.exec()

Un appel de méthode àRuntime.exec() est un moyen simple, pas encore personnalisable, de générer un nouveau sous-processus.

Dans l'exemple suivant, nous demanderons une liste de répertoires d'un répertoire de base d'utilisateurs et l'imprimerons sur la 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;

5. ProcessBuilder

Pour la deuxième implémentation de notre problème informatique, nous utiliserons unProcessBuilder. Cette méthode est préférable à l'approcheRuntime, car nous pouvons personnaliser certains détails.

Par exemple, nous pouvons:

  • changez le répertoire de travail que notre commande shell exécute en utilisantbuilder.directory()

  • configurer une carte clé-valeur personnalisée comme environnement à l'aide debuilder.environment()

  • rediriger les flux d'entrée et de sortie vers des remplacements personnalisés

  • hérite des deux dans les flux du processusJVM actuel en utilisantbuilder.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;

6. Conclusion

Comme nous l'avons vu dans ce rapide tutoriel, nous pouvons exécuter une commande shell dansJava de deux manières distinctes.

En règle générale, si vous prévoyez de personnaliser l’exécution du processus généré, par exemple pour changer son répertoire de travail, vous devriez envisager d’utiliser unProcessBuilder.

Comme toujours, vous trouverez les sourceson GitHub.