1. Обзор
В этом руководстве мы проиллюстрируем два способа выполнения команды оболочки из кода Java
.
Первый заключается в использовании класса Runtime
и вызове его метода exec .
Второй и более настраиваемый способ заключается в создании и использовании экземпляра ProcessBuilder
.
2. Зависимость от операционной системы
Прежде чем мы собираемся создать новый процесс
, выполняющий нашу команду оболочки, нам нужно сначала определить операционную систему, в которой работает наша JVM
.
Это потому, что в Windows
нам нужно запустить нашу команду в качестве аргумента для оболочки cmd.exe
, а во всех других операционных системах мы можем запустить стандартную оболочку с именем sh:
boolean isWindows = System.getProperty("os.name")
.toLowerCase().startsWith("windows");
3. Ввод и вывод
Кроме того ** ** , нам нужен способ подключения к входным и выходным потокам нашего процесса.
По крайней мере , вывод должен быть использован, иначе наш процесс не завершится успешно, а зависнет.
Давайте реализуем часто используемый класс StreamGobbler
, который использует 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);
}
}
ПРИМЕЧАНИЕ. Этот класс реализует интерфейс Runnable
, что означает, что его может выполнять любой Executor
.
4. Время выполнения.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
. Это предпочтительнее, чем подход Runtime
, потому что мы можем настроить некоторые детали.
Например, мы можем:
- измените рабочий каталог, в котором работает наша команда оболочки, используя
builder.directory()
- настроить пользовательскую карту ключ-значение как среду, используя
builder.environment()
- перенаправить потоки ввода и вывода на пользовательские замены
- наследовать их оба потокам текущего процесса
JVM
, используя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;
6. Заключение
Как мы видели в этом кратком руководстве, мы можем выполнить команду оболочки в Java
двумя различными способами.
Как правило, если вы планируете настроить выполнение порожденного процесса, например, изменить его рабочий каталог, вам следует рассмотреть возможность использования ProcessBuilder
.
Как всегда, вы найдете исходники на GitHub
.