Вопрос-ответ

Capturing stdout when calling Runtime.exec

Захват стандартного вывода при вызове Runtime.exec

При возникновении сетевых проблем на клиентских компьютерах я хотел бы иметь возможность запускать несколько командных строк и отправлять их результаты самому себе по электронной почте.

Я обнаружил, что Runtime.exec позволит мне выполнять произвольные команды, но собирать результаты в строку интереснее.

Я понимаю, что мог бы перенаправить вывод в файл, а затем прочитать из файла, но мое чутье подсказывает мне, что есть более элегантный способ сделать это.

Предложения?

Переведено автоматически
Ответ 1

Вам необходимо зафиксировать как std out, так и std err в процессе. Затем вы можете записать std out в файл / почту или что-то подобное.

Смотрите Эту статью для получения дополнительной информации и, в частности, обратите внимание на StreamGobbler механизм, который фиксирует стандартный вывод / ошибку в отдельных потоках. Это важно для предотвращения блокировки и является источником многочисленных ошибок, если вы не делаете это должным образом!

Ответ 2

Используйте ProcessBuilder. После вызова start() вы получите объект Process, из которого вы можете получить потоки stderr и stdout.

ОБНОВЛЕНИЕ: ProcessBuilder дает вам больше контроля; Вам не обязательно его использовать, но я нахожу это проще в долгосрочной перспективе. Особенно важна возможность перенаправлять stderr в стандартный вывод, что означает, что вам нужно отсосать только один поток.

Ответ 3

Для процессов, которые не генерируют много выходных данных, я думаю, этого простого решения, использующего Apache IOUtils, достаточно:

Process p = Runtime.getRuntime().exec("script");
p.waitFor();
String output = IOUtils.toString(p.getInputStream());
String errorOutput = IOUtils.toString(p.getErrorStream());

Предостережение: Однако, если ваш процесс генерирует много выходных данных, этот подход может вызвать проблемы, как упомянуто в классе процесса JavaDoc:


Созданный подпроцесс не имеет собственного терминала или консоли. Все его стандартные операции ввода-вывода (т.Е. stdin, stdout, stderr) будут перенаправлены родительскому процессу через три потока (getOutputStream(), getInputStream(), getErrorStream()). Родительский процесс использует эти потоки для передачи входных данных в подпроцесс и получения выходных данных из него. Поскольку некоторые собственные платформы предоставляют ограниченный размер буфера только для стандартных потоков ввода и вывода, неспособность своевременно записать входной поток или прочитать выходной поток подпроцесса может привести к блокировке подпроцесса и даже взаимоблокировке.


Ответ 4

Используйте Plexus Utils, он используется Maven для выполнения всех внешних процессов.

Commandline commandLine = new Commandline();
commandLine.setExecutable(executable.getAbsolutePath());

Collection<String> args = getArguments();

for (String arg : args) {
Arg _arg = commandLine.createArg();
_arg.setValue(arg);
}

WriterStreamConsumer systemOut = new WriterStreamConsumer(console);
WriterStreamConsumer systemErr = new WriterStreamConsumer(console);

returnCode = CommandLineUtils.executeCommandLine(commandLine, systemOut, systemErr, 10);
if (returnCode != 0) {
// bad
} else {
// good
}
java