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;
}
Я знаю, что этот вопрос старый, но я отправляю этот ответ, потому что думаю, что это может быть быстрее.
Ответ 3
Кроме использования ProcessBuilder
в качестве предлагаемого Senthil, обязательно прочитайте и выполните all рекомендации Когда Runtime.exec() не будет.
Ответ 4
@Senthil и @Arend answer (fooobar.com/questions/60828/...) упомянули ProcessBuilder
. Вот пример использования ProcessBuilder
с указанием переменных среды и рабочей папки для команды:
ProcessBuilder pb = new ProcessBuilder("ls", "-a", "-l");
Map<String, String> env = pb.environment();
// If you want clean environment, call env.clear() first
//env.clear();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
File workingFolder = new File("/home/user");
pb.directory(workingFolder);
Process proc = pb.start();
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);
Ответ 5
Также мы можем использовать потоки для получения выходных команд:
public static void main(String[] args) throws IOException {
Runtime runtime = Runtime.getRuntime();
String[] commands = {"free", "-h"};
Process process = runtime.exec(commands);
BufferedReader lineReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
lineReader.lines().forEach(System.out::println);
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
errorReader.lines().forEach(System.out::println);
}
Ответ 6
Если вы уже используете Apache commons-io на classpath, вы можете использовать:
Process p = new ProcessBuilder("cat", "/etc/something").start();
String stderr = IOUtils.toString(p.getErrorStream(), Charset.defaultCharset());
String stdout = IOUtils.toString(p.getInputStream(), Charset.defaultCharset());
Ответ 7
На момент написания этой статьи все остальные ответы, содержащие код, могут привести к взаимоблокировке.
Процессы имеют ограниченный буфер для вывода 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
. Если вы хотите реализовать это вручную, вам придется использовать потоки в двух разных потоках, чтобы никогда не блокировать.
Ответ 8
Адаптировано из предыдущего ответа:
public static String execCmdSync(String cmd, CmdExecResult callback) throws java.io.IOException, InterruptedException {
RLog.i(TAG, "Running command:", cmd);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
//String[] commands = {"system.exe", "-get t"};
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
StringBuffer stdOut = new StringBuffer();
StringBuffer errOut = new StringBuffer();
// 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);
stdOut.append(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);
errOut.append(s);
}
if (callback == null) {
return stdInput.toString();
}
int exitVal = proc.waitFor();
callback.onComplete(exitVal == 0, exitVal, errOut.toString(), stdOut.toString(), cmd);
return stdInput.toString();
}
public interface CmdExecResult{
void onComplete(boolean success, int exitVal, String error, String output, String originalCmd);
}
Ответ 9
Практически так же, как и другие фрагменты на этой странице, но просто упорядочиваем все по функции, здесь мы...
String str=shell_exec("ls -l");
Функция класса:
public String shell_exec(String cmd)
{
String o=null;
try
{
Process p=Runtime.getRuntime().exec(cmd);
BufferedReader b=new BufferedReader(new InputStreamReader(p.getInputStream()));
String r;
while((r=b.readLine())!=null)o+=r;
}catch(Exception e){o="error";}
return o;
}
Ответ 10
Попробуйте прочитать InputStream
среды выполнения:
Runtime rt = Runtime.getRuntime();
String[] commands = {"system.exe", "-send", argument};
Process proc = rt.exec(commands);
BufferedReader br = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
String line;
while ((line = br.readLine()) != null)
System.out.println(line);
Вам также может понадобиться прочитать поток ошибок (proc.getErrorStream()
), если процесс печатает вывод ошибок. Вы можете перенаправить поток ошибок во входной поток, если вы используете ProcessBuilder
.