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

Java Runtime.getRuntime(): getting output from executing a command line program

Java Runtime.getRuntime(): получение выходных данных при выполнении программы из командной строки

Я использую среду выполнения для запуска команд командной строки из моей Java-программы. Однако я не знаю, как я могу получить выходные данные, которые возвращает команда.

Вот мой код:

Runtime rt = Runtime.getRuntime();

String[] commands = {"system.exe", "-send" , argument};

Process proc = rt.exec(commands);

Я пытался сделать System.out.println(proc); но это ничего не вернуло. Выполнение этой команды должно вернуть два числа, разделенные точкой с запятой. Как я мог бы получить это в переменной для распечатки?

Вот код, который я использую сейчас:

String[] commands = {"system.exe", "-get t"};

Process proc = rt.exec(commands);

InputStream stdIn = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(stdIn);
BufferedReader br = new BufferedReader(isr);

String line = null;
System.out.println("<OUTPUT>");

while ((line = br.readLine()) != null)
System.out.println(line);

System.out.println("</OUTPUT>");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);

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

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

Вот как поступить:

Runtime rt = Runtime.getRuntime();
String[] commands = {"system.exe", "-get t"};
Process proc = rt.exec(commands);

BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));

BufferedReader stdError = new BufferedReader(new
InputStreamReader(proc.getErrorStream()));

// Read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}

// Read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}

Прочитайте Javadoc для получения более подробной информации здесь. ProcessBuilder было бы хорошим выбором для использования.

Ответ 2

Более быстрый способ заключается в следующем:

public static String execCmd(String cmd) throws java.io.IOException {
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}

Которая в основном представляет собой сокращенную версию этого:

public static String execCmd(String cmd) throws java.io.IOException {
Process proc = Runtime.getRuntime().exec(cmd);
java.io.InputStream is = proc.getInputStream();
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
String val = "";
if (s.hasNext()) {
val = s.next();
}
else {
val = "";
}
return val;
}

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

Редактировать (Для Java 7 и выше)

Необходимо закрыть потоки и сканеры. Использование AutoCloseable для аккуратного кода:

public static String execCmd(String cmd) {
String result = null;
try (InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
Scanner s = new Scanner(inputStream).useDelimiter("\\A")) {
result = s.hasNext() ? s.next() : null;
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
Ответ 3

Если в пути к классу Apache commons-io уже доступен, вы можете использовать:

Process p = new ProcessBuilder("cat", "/etc/something").start();
String stderr = IOUtils.toString(p.getErrorStream(), Charset.defaultCharset());
String stdout = IOUtils.toString(p.getInputStream(), Charset.defaultCharset());
Ответ 4

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

Процессы имеют ограниченный буфер для stdout и stderr выходных данных. Если вы не будете прослушивать их одновременно, один из них заполнится, пока вы пытаетесь прочитать другой. Например, вы могли ожидать чтения из stdout в то время как процесс ожидает записи в stderr. Вы не можете читать из stdout буфера, потому что он пуст, и процесс не может выполнять запись в stderr буфер, потому что он заполнен. Вы вечно ждете друг друга.

Вот возможный способ считывания выходных данных процесса без риска взаимоблокировок:

public final class Processes
{
private static final String NEWLINE = System.getProperty("line.separator");

/**
* @param command the command to run
* @return the output of the command
* @throws IOException if an I/O error occurs
*/

public static String run(String... command) throws IOException
{
ProcessBuilder pb = new ProcessBuilder(command).redirectErrorStream(true);
Process process = pb.start();
StringBuilder result = new StringBuilder(80);
try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())))
{
while (true)
{
String line = in.readLine();
if (line == null)
break;
result.append(line).append(NEWLINE);
}
}
return result.toString();
}

/**
* Prevent construction.
*/

private Processes()
{
}
}

Ключ в том, чтобы использовать ProcessBuilder.redirectErrorStream(true) который перенаправит stderr в stdout поток. Это позволяет вам читать один поток без необходимости чередовать stdout и stderr. Если вы хотите реализовать это вручную, вам придется использовать потоки в двух разных потоках, чтобы убедиться, что вы никогда не заблокируете.

2023-06-30 18:29 java