Actualización: Este artículo ha sido sustituido por mi artículo más reciente «Java exec con ProcessBuilder y Process». Mientras que el código Java mostrado en este tutorial funciona en casos simples de «Java exec», el nuevo artículo muestra cómo leer correctamente los flujos de salida de su comando de sistema en hilos Java, y también cómo escribir en la entrada estándar de su comando, si es necesario.

No dudes en leer este artículo para obtener información de fondo/legado, pero te recomiendo encarecidamente que utilices el código fuente que comparto en mi artículo más reciente sobre «Java exec», porque resuelve los problemas de entrada y salida estándar y de errores que no manejé correctamente en el código que aparece a continuación.

Introducción

He leído mucho sobre Java, pero una de las cosas que rara vez veo que se discuta es cómo debes hacer para ejecutar comandos externos del sistema. Por supuesto, probablemente no leas mucho sobre esto porque le resta portabilidad a las aplicaciones Java. Por ejemplo, si escribes una aplicación Java en un sistema Unix, podrías estar interesado en ejecutar el comando «ps -ef», y leer la salida del comando. Para los sistemas Unix esto es genial, pero desafortunadamente, este mismo programa no funcionará en un sistema Windows porque el comando ps no está disponible en Windows.

Bueno, vamos a olvidarnos de la portabilidad para este artículo, y demostrar un método que puede ser utilizado para ejecutar comandos del sistema. Hemos recibido un montón de peticiones sobre este tema, así que aquí va.

Discusión (Runtime exec and Process)

Ejecutar un comando de sistema es relativamente sencillo – una vez que lo has visto hacer la primera vez. Implica el uso de dos clases Java, la clase Runtime y la clase Process. Básicamente, se utiliza el método exec de la clase Runtime para ejecutar el comando como un proceso separado. La invocación del método exec devuelve un objeto Process para gestionar el subproceso. Luego se utilizan los métodos getInputStream() y getErrorStream() del objeto Process para leer la salida normal del comando, y la salida de error del comando. Lo que hagas con la salida del comando ejecutado depende totalmente de ti y de la aplicación que estés creando.

(Nota: También hay un método getOutputStream() que puedes usar para escribir en el proceso, pero no cubriremos ese método en este artículo. Cubriremos eso y algunas otras características avanzadas en un futuro artículo.)

Un ejemplo de Java exec

El código mostrado en el Listado 1 proporciona un ejemplo de trabajo de nuestra técnica «Java exec» en un archivo llamado JavaRunCommand.java.

import java.io.*;public class JavaRunCommand { public static void main(String args) { String s = null; try { // run the Unix "ps -ef" command // using the Runtime exec method: Process p = Runtime.getRuntime().exec("ps -ef"); BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream())); // read the output from the command System.out.println("Here is the standard output of the command:\n"); 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); } System.exit(0); } catch (IOException e) { System.out.println("exception happened - here's what I know: "); e.printStackTrace(); System.exit(-1); } }}

Listado 1 (arriba): El archivo JavaRunCommand.java muestra cómo se puede ejecutar un comando externo del sistema desde un programa Java.

Cómo funciona nuestro código Java exec

Lo primero que se hace es especificar el comando que se quiere ejecutar suministrando este comando a la clase Runtime. Como no puedes crear tu propia instancia de la clase Runtime, primero utilizas el método getRuntimepara acceder al entorno de ejecución actual y luego invocas el método exec de Runtime. Esto devuelve un objeto Process.

Todo lo demás que hagas implica métodos del objeto Process. En este caso, como estamos ejecutando el comando «ps -ef» en un sistema Unix, sólo necesitamos leer la salida del comando. Leer el error estándar probablemente no es necesario en este caso, pero pensé que al menos valía la pena mostrarlo, si no es una buena práctica de programación.

Convierto los flujos de entrada con el InputStreamReader y BufferedReader para poder usar el método readLine() de la clase BufferedReader. Debido a que uso estas clases, esta aplicación no compilará correctamente con un compilador JDK 1.0.x más antiguo (estas clases no estaban disponibles en 1.0.x).

Descarga el código fuente del ejemplo «Java exec»

Podría extenderme mucho sobre este tema, pero lo mejor que puedo recomendarte es que descargues el código fuente y trabajes con él durante un tiempo. Prueba a ejecutar diferentes comandos para ver si consigues que funcionen correctamente, e intenta ejecutar un comando que requiera entrada (esto será un poco más complicado).