Java Runtime.getRuntime(): obtener resultados al ejecutar un programa de línea de comandos

Resuelto user541597 asked hace 13 años • 13 respuestas

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.

user541597 avatar Apr 19 '11 09:04 user541597
Aceptado

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í . ProcessBuilderSería una buena opción para usar.

Senthil avatar Apr 19 '2011 03:04 Senthil

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;
}
735Tesla avatar Dec 17 '2013 02:12 735Tesla

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());
whirlwin avatar Sep 28 '2018 11:09 whirlwin

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 stdouty stderrsalida. 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 stdoutmientras el proceso espera para escribir en stderr. No puede leer del stdoutbúfer porque está vacío y el proceso no puede escribir en el stderrbú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á stderra la stdoutsecuencia. Esto le permite leer una sola secuencia sin tener que alternar entre stdouty stderr. Si desea implementar esto manualmente, deberá consumir las transmisiones en dos subprocesos diferentes para asegurarse de no bloquear nunca.

Gili avatar Sep 16 '2019 02:09 Gili

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);
    }
Jackkobec avatar Mar 12 '2018 22:03 Jackkobec