Автор оригинала: David Landup.
Вступление
В этой статье мы рассмотрим, как мы можем использовать классы Runtime
и ProcessBuilder
для выполнения команд и сценариев оболочки с помощью Java.
Мы используем компьютеры для автоматизации многих вещей в нашей повседневной работе. Системные администраторы постоянно выполняют множество команд, некоторые из которых очень повторяющиеся и требуют минимальных изменений в промежутках между запусками.
Этот процесс также созрел для автоматизации. Нет необходимости запускать все вручную. Используя Java, мы можем запускать одну или несколько команд оболочки, выполнять сценарии оболочки, запускать терминал/командную строку, устанавливать рабочие каталоги и управлять переменными среды с помощью основных классов.
Время выполнения.exec()
Класс Runtime
в Java-это класс высокого уровня, присутствующий в каждом отдельном приложении Java. Через него само приложение взаимодействует с окружающей средой, в которой оно находится.
Извлекая среду выполнения, связанную с нашим приложением, с помощью метода getRuntime ()
, мы можем использовать метод exec()
для прямого выполнения команд или запуска файлов .bat
/|. sh .
Метод exec()
предлагает несколько перегруженных вариантов:
публичный процесс exec(строковая команда)
– Выполняет команду, содержащуюся вcommand
, в отдельном процессе.публичный процесс exec(строковая команда, Строка[] envp)
– Выполняет команду| с массивом переменных среды. Они представлены в виде массива строк, следующих за форматом
имя=значение.
публичный процесс exec(Строковая команда, Строка[] envp, директория файла)- Выполняет
командус указанными переменными среды из каталога
| каталога.публичный процесс exec(Строка cmdArray[])
– Выполняет команду в виде массива строк.публичный процесс exec(Строка cmdArray[], Строка[] envp)
– Выполняет команду с указанными переменными среды.публичный процесс exec(Строка cmdarray[], Строка[] envp, файл dir)
– Выполняет команду с указанными переменными среды из каталогаdir
.
Стоит отметить, что эти процессы запускаются извне из интерпретатора и будут зависеть от системы.
Что также стоит отметить, так это разницу между Строковой командой
и Строковой командой cmdArray[]
. Они достигают одного и того же. Команда | в любом случае разбивается на массив, поэтому использование любого из этих двух должно привести к одинаковым результатам.
Вам решать, хотите ли вы использовать exec("директория/папка")
или exec(новая строка[]{"директория", "/папка"}
.
Давайте приведем несколько примеров, чтобы увидеть, чем эти перегруженные методы отличаются друг от друга.
Выполнение команды из строки
Давайте начнем с самого простого подхода из этих трех:
Process process = Runtime.getRuntime().exec("ping www.stackabuse.com");
Запуск этого кода приведет к выполнению команды, которую мы предоставили в строковом формате. Однако мы ничего не видим, когда запускаем это.
Чтобы проверить, правильно ли это выполнено, мы захотим получить доступ к объекту process
. Давайте воспользуемся BufferedReader
, чтобы взглянуть на то, что происходит:
public static void printResults(Process process) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = ""; while ((line = reader.readLine()) != null) { System.out.println(line); } }
Теперь, когда мы запускаем этот метод после метода exec ()
, он должен дать что-то вроде:
Pinging www.stackabuse.com [104.18.57.23] with 32 bytes of data: Reply from 104.18.57.23: bytes=32 time=21ms TTL=56 Reply from 104.18.57.23: bytes=32 time=21ms TTL=56 Reply from 104.18.57.23: bytes=32 time=21ms TTL=56 Reply from 104.18.57.23: bytes=32 time=21ms TTL=56 Ping statistics for 104.18.57.23: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 21ms, Maximum = 21ms, Average = 21ms
Имейте в виду, что нам придется извлекать информацию о процессе из экземпляров Process
, когда мы будем рассматривать другие примеры.
Укажите рабочий каталог
Если вы хотите запустить команду, скажем, из определенной папки, мы бы сделали что-то вроде:
Process process = Runtime.getRuntime() .exec("cmd /c dir", null, new File("C:\\Users\\")); //.exec("sh -c ls", null, new File("Pathname")); for non-Windows users printResults(process);
Здесь мы предоставили методу exec()
команду ,
null для новых переменных среды и
новый файл () , который установлен в качестве вашего рабочего каталога.
Стоит отметить добавление cmd/c
перед такой командой, как dir
.
Поскольку я работаю в Windows, это открывает cmd
и /c
выполняет последующую команду. В данном случае это реж.
.
Причина, по которой это не было обязательным для примера ping
, но является обязательным для этого примера, хорошо ответил пользователь SO.
Запуск предыдущего фрагмента кода приведет к:
Volume in drive C has no label. Volume Serial Number is XXXX-XXXX Directory of C:\Users 08/29/2019 05:01 PM. 08/29/2019 05:01 PM .. 08/18/2016 09:11 PM Default.migrated 08/29/2019 05:01 PM Public 05/15/2020 11:08 AM User 0 File(s) 0 bytes 5 Dir(s) 212,555,214,848 bytes free
Давайте посмотрим, как мы могли бы предоставить предыдущую команду в нескольких отдельных частях, а не в одной строке:
Process process = Runtime.getRuntime().exec( new String[]{"cmd", "/c", "dir"}, null, new File("C:\\Users\\")); printResults(process);
Запуск этого фрагмента кода также приведет к:
Volume in drive C has no label. Volume Serial Number is XXXX-XXXX Directory of C:\Users 08/29/2019 05:01 PM. 08/29/2019 05:01 PM .. 08/18/2016 09:11 PM Default.migrated 08/29/2019 05:01 PM Public 05/15/2020 11:08 AM User 0 File(s) 0 bytes 5 Dir(s) 212,542,808,064 bytes free
В конечном счете, независимо от подхода – с использованием одной строки или массива строк, вводимая вами команда всегда будет разбита на массив перед обработкой базовой логикой.
Какой из них вы хотели бы использовать, сводится только к тому, какой из них вы считаете более читабельным.
Использование Переменных Среды
Давайте посмотрим, как мы можем использовать переменные среды:
Process process = Runtime.getRuntime().exec( "cmd /c echo %var1%", new String[]{"var1=value1"}); printResults(process);
Мы можем предоставить столько переменных среды, сколько захотим, в строковом массиве. Здесь мы только что напечатали значение var1
, используя echo
.
Выполнение этого кода вернет:
value1
Запуск файлов .bat и .sh
Иногда просто гораздо проще выгрузить все в файл и запустить этот файл вместо того, чтобы добавлять все программно.
В зависимости от вашей операционной системы вы будете использовать файлы .bat
или|/. sh|/. Давайте создадим его с содержимым:
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
echo Hello World
Тогда давайте воспользуемся тем же подходом, что и раньше:
Process process = Runtime.getRuntime().exec( "cmd /c start file.bat", null, new File("C:\\Users\\User\\Desktop\\"));
Это откроет командную строку и запустит файл .bat
в заданном нами рабочем каталоге.
Запуск этого кода, несомненно, приведет к:
Теперь, когда все перегруженные exec()
подписи устранены, давайте рассмотрим класс ProcessBuilder
и то, как мы можем выполнять команды с его помощью.
Конструктор процессов
ProcessBuilder
является базовым механизмом, который выполняет команды при использовании метода Runtime.getRuntime().exec()
:
/** * Executes the specified command and arguments in a separate process with * the specified environment and working directory. *... */ public Process exec(String[] cmdarray, String[] envp, File dir) throws IOException { return new ProcessBuilder(cmdarray) .environment(envp) .directory(dir) .start(); }
JavaDocs для Время выполнения класс
Взглянув на то, как ProcessBuilder
принимает наши входные данные из метода exec()
и запускает команду, мы также получаем хорошее представление о том, как ее использовать.
Он принимает строку [] cmdarray
, и этого достаточно, чтобы запустить его. В качестве альтернативы мы можем предоставить ему дополнительные аргументы, такие как String[] envp
и File dir
.
Давайте рассмотрим эти варианты.
ProcessBuilder: Выполнение команды из строк
Вместо того, чтобы предоставлять одну строку , такую как cmd/c dir
, в этом случае нам придется разбить ее. Например, если бы мы хотели перечислить файлы в C:/Users
каталог, как и раньше, мы бы сделали:
ProcessBuilder processBuilder = new ProcessBuilder(); processBuilder.command("cmd", "/c", "dir C:\\Users"); Process process = processBuilder.start(); printResults(process);
Чтобы фактически выполнить Процесс
, мы запускаем команду start()
и присваиваем возвращаемое значение экземпляру Процесса
.
Запуск этого кода приведет к:
Volume in drive C has no label. Volume Serial Number is XXXX-XXXX Directory of C:\Users 08/29/2019 05:01 PM. 08/29/2019 05:01 PM .. 08/18/2016 09:11 PM Default.migrated 08/29/2019 05:01 PM Public 05/15/2020 11:08 AM User 0 File(s) 0 bytes 5 Dir(s) 212,517,294,080 bytes free
Однако этот подход ничем не лучше предыдущего. Что полезно в классе ProcessBuilder
, так это то, что он настраивается. Мы можем устанавливать вещи программно, а не только с помощью команд.
ProcessBuilder: Укажите рабочий каталог
Вместо того, чтобы указывать рабочий каталог с помощью команды, давайте установим его программно:
processBuilder.command("cmd", "/c", "dir").directory(new File("C:\\Users\\"));
Здесь мы установили рабочий каталог таким же, как и раньше, но мы удалили это определение из самой команды. Выполнение этого кода даст тот же результат, что и в предыдущем примере.
ProcessBuilder: Переменные среды
Используя методы ProcessBuilder
, легко получить список переменных среды в виде Карты
. Также легко установить переменные среды, чтобы ваша программа могла их использовать.
Давайте получим переменные среды, доступные в настоящее время, а затем добавим некоторые для последующего использования:
ProcessBuilder processBuilder = new ProcessBuilder(); MapenvironmentVariables = processBuilder.environment(); environmentVariables.forEach((key, value) -> System.out.println(key + value));
Здесь мы упаковали возвращенные переменные среды в Map
и запустили forEach()
на нем, чтобы распечатать значения на нашей консоли.
Выполнение этого кода приведет к получению списка переменных среды, имеющихся на вашем компьютере:
DriverDataC:\Windows\System32\Drivers\DriverData HerokuPathE:\Heroku ProgramDataC:\ProgramData ...
Теперь давайте добавим переменную среды в этот список и будем использовать ее:
environmentVariables.put("var1", "value1"); processBuilder.command("cmd", "/c", "echo", "%var1%"); Process process = processBuilder.start(); printResults(process);
Запуск этого кода приведет к:
value1
Конечно, как только программа завершит работу, эта переменная не останется в списке.
ProcessBuilder: Запуск файлов .bat и .sh
Если вы хотите снова запустить файл, мы просто предоставим экземпляру ProcessBuilder
необходимую информацию:
processBuilder .command("cmd", "/c", "start", "file.bat") .directory(new File("C:\\Users\\User\\Desktop")); Process process = processBuilder.start();
Выполнение этого кода приводит к открытию командной строки и выполнению файла .bat
.:
Вывод
В этой статье мы рассмотрели примеры выполнения команд оболочки на Java. Для этого мы использовали классы Runtime
и ProcessBuilder
.
Используя Java, мы можем запускать одну или несколько команд оболочки, выполнять сценарии оболочки, запускать терминал/командную строку, устанавливать рабочие каталоги и управлять переменными среды с помощью основных классов.