Java Runtime.getRuntime(): obtener resultados al ejecutar un programa de línea de comandos
Estoy usando el tiempo de ejecución para ejecutar comandos del símbolo del sistema desde mi programa Java. Sin embargo, no sé cómo puedo obtener el resultado que devuelve el comando.
Aquí está mi código:
Runtime rt = Runtime.getRuntime();
String[] commands = {"system.exe", "-send" , argument};
Process proc = rt.exec(commands);
Intenté hacerlo System.out.println(proc);
pero no devolvió nada. La ejecución de ese comando debería devolver dos números separados por un punto y coma. ¿Cómo podría incluir esto en una variable para imprimir?
Aquí está el código que estoy usando ahora:
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);
Pero no obtengo nada como resultado, pero cuando ejecuto ese comando yo mismo funciona bien.
Este es el camino a seguir:
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);
}
Lea el Javadoc para obtener más detalles aquí . ProcessBuilder
Sería una buena opción para usar.
Una forma más rápida es esta:
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() : "";
}
Que es básicamente una versión condensada de esto:
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;
}
Sé que esta pregunta es antigua, pero publico esta respuesta porque creo que puede ser más rápido.
Editar (para Java 7 y superior)
Es necesario cerrar Streams y Scanners. Usando AutoCloseable para un código ordenado:
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;
}
Si ya tiene Apache commons-io disponible en el classpath, puede usar:
Process p = new ProcessBuilder("cat", "/etc/something").start();
String stderr = IOUtils.toString(p.getErrorStream(), Charset.defaultCharset());
String stdout = IOUtils.toString(p.getInputStream(), Charset.defaultCharset());
En el momento de escribir este artículo, todas las demás respuestas que incluyan código pueden provocar puntos muertos.
Los procesos tienen un buffer limitado para stdout
y stderr
salida. Si no los escuchas al mismo tiempo, uno de ellos se llenará mientras intentas leer el otro. Por ejemplo, podría estar esperando para leer stdout
mientras el proceso espera para escribir en stderr
. No puede leer del stdout
búfer porque está vacío y el proceso no puede escribir en el stderr
búfer porque está lleno. Cada uno de ustedes se espera el uno al otro para siempre.
A continuación se muestra una forma posible de leer el resultado de un proceso sin riesgo de bloqueos:
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()
{
}
}
La clave es usar ProcessBuilder.redirectErrorStream(true)
el cual redirigirá stderr
a la stdout
secuencia. Esto le permite leer una sola secuencia sin tener que alternar entre stdout
y stderr
. Si desea implementar esto manualmente, deberá consumir las transmisiones en dos subprocesos diferentes para asegurarse de no bloquear nunca.
También podemos usar transmisiones para obtener la salida del comando:
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);
}