1. Обзор
В этом уроке мы проиллюстрируем два способа выполнения команды оболочки из Java кода .
Первый-использовать класс Runtime и вызвать его метод exec .
Вторым и более настраиваемым способом будет создание и использование экземпляра ProcessBuilder .
2. Зависимость от операционной системы
Прежде чем мы создадим новый Процесс , выполняющий нашу команду оболочки, нам нужно сначала определить операционную систему, в которой работает наша JVM .
Это потому, что в Windows нам нужно запустить вашу команду в качестве аргумента для cmd.exe shell и на всех других операционных системах мы можем выпустить стандартную оболочку, называемую sh:
boolean isWindows = System.getProperty("os.name") .toLowerCase().startsWith("windows");
3. Вход и выход
Кроме того, нам нужен способ подключения к входным и выходным потокам нашего процесса.
По крайней мере вывод должен быть потреблен – в противном случае наш процесс не вернется успешно, вместо этого он зависнет.
Давайте реализуем обычно используемый класс под названием StreamGobbler , который потребляет InputStream :
private static class StreamGobbler implements Runnable { private InputStream inputStream; private Consumerconsumer; public StreamGobbler(InputStream inputStream, Consumer consumer) { this.inputStream = inputStream; this.consumer = consumer; } @Override public void run() { new BufferedReader(new InputStreamReader(inputStream)).lines() .forEach(consumer); } }
ПРИМЕЧАНИЕ: Этот класс реализует интерфейс Runnable , что означает, что он может быть выполнен любым Исполнителем .
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
Для второй реализации нашей вычислительной задачи мы будем использовать ProcessBuilder . Это предпочтительнее, чем подход Runtime , потому что мы можем настроить некоторые детали.
Например, мы можем:
- измените рабочий каталог, в котором выполняется команда оболочки, с помощью builder.directory()
- настройка пользовательской карты ключ-значение в качестве среды с помощью builder.environment()
- перенаправление потоков ввода и вывода на пользовательские замены
- унаследуйте их оба в потоках текущего JVM процесса с помощью builder.inherited()
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. Заключение
Как мы видели в этом кратком руководстве, мы можем выполнить команду оболочки в Java двумя различными способами.
Как правило, если вы планируете настроить выполнение порожденного процесса, например, изменить его рабочий каталог, вам следует рассмотреть возможность использования ProcessBuilder .
Как всегда, вы найдете источники на GitHub .