jump to navigation

Ejecutar Shell Scripts desde Java marzo 14, 2007

Posted by superpiwi in Java, Oracle, Programacion, Unix.
trackback

Y ya que hemos hablado en el Post anterior de Shell Scripts, porque no ejecutarlos directamente desde codigo fuente con Java. Antes de nada recomiendo una lectura:

When Runtime.exec() won’t

En este caso he creado una clase propia «Script.java» y he adaptado la del ejemplo que aparece en el articulo anterior.

Esta clase Script nos permite ejecutar comandos y shell scripts empleando el interprete de comandos.

Por ejemplo el siguiente codigo:


Script sc = new Script();
sc.setVerbose(true);
String CONTENT = "sqlplus2\nls -l\nps\necho \"End\\nFin\"";
String OUTPUT = sc.executeScript(CONTENT,
"/home/jose/Desktop/MiScript.sh", true);
System.out.println(OUTPUT);
String ERROR = sc.getError();
System.out.println("**ERROR**" + ERROR);

Como observais estoy lanzando la ejecucion de estos tres comandos:


sqlplus2 (que no existe y dara error)
ls -l
ps
y un echo End salto de linea Fin

Al ejecutar este codigo desde java nos devolveria lo siguiente:


ERROR> /home/jose/Desktop/MiScript.sh: 1: sqlplus2: not found
OUTPUT> total 44
OUTPUT> drwxr-xr-x 3 jose jose 4096 2007-01-11 09:18 ant
OUTPUT> drwxr-xr-x 6 jose jose 4096 2007-02-01 17:34 build
OUTPUT> -rw-r--r-- 1 jose jose 12953 2007-02-01 17:34 build.xml
OUTPUT> drwxr-xr-x 2 jose jose 4096 2007-01-11 09:17 CVS
OUTPUT> drwxr-xr-x 7 jose jose 4096 2007-01-11 09:17 Documentacion
OUTPUT> drwxr-xr-x 7 jose jose 4096 2007-01-11 09:17 JavaSource
OUTPUT> -rwxr-xr-x 1 jose jose 111 2007-03-14 17:13 pepe.sh
OUTPUT> drwxr-xr-x 11 jose jose 4096 2007-02-20 15:52 WebContent
OUTPUT> PID TTY TIME CMD
OUTPUT> 4887 ? 00:00:00 gconfd-2
OUTPUT> 11652 ? 00:00:00 x-session-manag
OUTPUT> 11665 ? 00:00:02 Scribe.exe <defunct>
OUTPUT> 11693 ? 00:00:00 ssh-agent
OUTPUT> 11696 ? 00:00:00 dbus-daemon
OUTPUT> 11697 ? 00:00:00 dbus-launch
OUTPUT> 11700 ? 00:00:00 gnome-keyring-d
OUTPUT> 11703 ? 00:00:03 gnome-settings-
OUTPUT> 11727 ? 00:00:27 metacity
OUTPUT> 11732 ? 00:00:23 gnome-panel
OUTPUT> 11734 ? 00:00:15 nautilus
OUTPUT> 11738 ? 00:00:00 bonobo-activati
OUTPUT> 11741 ? 00:00:00 gnome-vfs-daemo
OUTPUT> 11747 ? 00:00:00 update-notifier
OUTPUT> 11749 ? 00:00:00 gnome-volume-ma
OUTPUT> 11751 ? 00:00:00 evolution-alarm
OUTPUT> 11759 ? 00:00:10 trackerd
OUTPUT> 11762 ? 00:00:15 gnome-cups-icon
OUTPUT> 11774 ? 00:00:02 python
OUTPUT> 11776 ? 00:00:00 trashapplet
OUTPUT> 11779 ? 00:00:00 evolution-data-
OUTPUT> 11803 ? 00:00:00 evolution-excha
OUTPUT> 11833 ? 00:00:00 mapping-daemon
OUTPUT> 11834 ? 00:00:00 gnome-power-man
OUTPUT> 11843 ? 00:00:00 mixer_applet2
OUTPUT> 11885 ? 00:00:02 notification-da
OUTPUT> 11912 ? 00:00:05 gnome-screensav
OUTPUT> 12025 ? 00:01:49 skype
OUTPUT> 12094 ? 00:04:30 firefox-bin
OUTPUT> 12270 ? 00:00:00 eclipse
OUTPUT> 12276 ? 00:03:44 java
OUTPUT> 14360 ? 00:00:03 gnome-terminal
OUTPUT> 14369 ? 00:00:00 gnome-pty-helpe
OUTPUT> 14597 ? 00:01:59 wineserver
OUTPUT> 14599 ? 00:00:00 explorer.exe
OUTPUT> 17598 ? 00:00:00 java
OUTPUT> 17617 ? 00:00:00 sh
OUTPUT> 17618 ? 00:00:00 sh
OUTPUT> 17622 ? 00:00:00 ps
OUTPUT> End
OUTPUT> Fin
total 44
drwxr-xr-x 3 jose jose 4096 2007-01-11 09:18 ant
drwxr-xr-x 6 jose jose 4096 2007-02-01 17:34 build
-rw-r--r-- 1 jose jose 12953 2007-02-01 17:34 build.xml
drwxr-xr-x 2 jose jose 4096 2007-01-11 09:17 CVS
drwxr-xr-x 7 jose jose 4096 2007-01-11 09:17 Documentacion
drwxr-xr-x 7 jose jose 4096 2007-01-11 09:17 JavaSource
-rwxr-xr-x 1 jose jose 111 2007-03-14 17:13 pepe.sh
drwxr-xr-x 11 jose jose 4096 2007-02-20 15:52 WebContent
PID TTY TIME CMD
4887 ? 00:00:00 gconfd-2
11652 ? 00:00:00 x-session-manag
11665 ? 00:00:02 Scribe.exe <defunct>
11693 ? 00:00:00 ssh-agent
11696 ? 00:00:00 dbus-daemon
11697 ? 00:00:00 dbus-launch
11700 ? 00:00:00 gnome-keyring-d
11703 ? 00:00:03 gnome-settings-
11727 ? 00:00:27 metacity
11732 ? 00:00:23 gnome-panel
11734 ? 00:00:15 nautilus
11738 ? 00:00:00 bonobo-activati
11741 ? 00:00:00 gnome-vfs-daemo
11747 ? 00:00:00 update-notifier
11749 ? 00:00:00 gnome-volume-ma
11751 ? 00:00:00 evolution-alarm
11759 ? 00:00:10 trackerd
11762 ? 00:00:15 gnome-cups-icon
11774 ? 00:00:02 python
11776 ? 00:00:00 trashapplet
11779 ? 00:00:00 evolution-data-
11803 ? 00:00:00 evolution-excha
11833 ? 00:00:00 mapping-daemon
11834 ? 00:00:00 gnome-power-man
11843 ? 00:00:00 mixer_applet2
11885 ? 00:00:02 notification-da
11912 ? 00:00:05 gnome-screensav
12025 ? 00:01:49 skype
12094 ? 00:04:30 firefox-bin
12270 ? 00:00:00 eclipse
12276 ? 00:03:44 java
14360 ? 00:00:03 gnome-terminal
14369 ? 00:00:00 gnome-pty-helpe
14597 ? 00:01:59 wineserver
14599 ? 00:00:00 explorer.exe
17598 ? 00:00:00 java
17617 ? 00:00:00 sh
17618 ? 00:00:00 sh
17622 ? 00:00:00 ps
End
**ERROR**/home/jose/Desktop/MiScript.sh: 1: sqlplus2: not found

Sencillo y potente!!!

Tambien permite ejecutar shell scripts creandolos dinamicamente. esto por ejemplo nos sirve para lanzar scripts que solo contienen sentencias SQL. Por ejemplo el siguiente caso:


Script sql = new Script();
sql.setVerbose(false);
sql.setAddSHELLHEADER(true);
sql.setSHELLHEADER("#!/bin/sh");
//sql.setRUTA("/home/jose/Desktop");
CONTENT = "SELECT sysdate FROM DUAL;\nSELECT sysdate FECHA_HOY FROM DUAL;";
OUTPUT = sql.executeSQLScript(CONTENT, "EVO", "EVO", "EVODES",
null, "/home/jose/Desktop/MiSQL.sh", false);
System.out.println(OUTPUT);
ERROR = sql.getError();
System.out.println("**ERROR**" + ERROR);

Que nos devolveria:


SQL*Plus: Release 10.2.0.3.0 - Production on Wed Mar 14 17:38:06 2007
Copyright (c) 1982, 2006, Oracle. All Rights Reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production
With the Partitioning option
JServer Release 9.2.0.8.0 - Production
SQL>
SYSDATE
---------
14-MAR-07
SQL>
FECHA_HOY
---------
14-MAR-07
SQL> Disconnected from Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production
With the Partitioning option
JServer Release 9.2.0.8.0 - Production
**ERROR**

Aqui el truco es generar dinamicamente un fichero .sh con el contenido que se quiere ejecutar y luego lanzar el interprete de comandos para ejecutar ese fichero creado dinamicamente.

Pero mejor veis las clases y ya trasteais con ellas. Aqui las dejo.

StreamGlobber.java


/**
* StramGobbler.java
*
* Para capturar la salida de la ejecucion del comando.
*
* @modified clase original de javaworld modificada por jdelgado
* @version 0.0.0.2 - 13 Marzo 2007
* @sinde JDK 1.5 - Eclipse 3.2
*/
package comun.util.unix;
import java.io.*;
class StreamGobbler extends Thread {
// Flujo de entrada
InputStream is;
// Tipo de Flujo: generalmente output o error
String type;
// Flujo de salida
OutputStream os;
// Variable para mostrar por la salida estandard
boolean debug = false;
// para guardar la salida generada
String output = "";
// ----
/**
* Constructor
*
* @param is
* InputStream
* @param type
* tipo de flujo (OUTPUT o ERROR)
* @param debug
* indica si se debe mostrar o no la salida por la salida
* estandard
*/
StreamGobbler(InputStream is, String type, boolean debug) {
this(is, type, null, debug);
}
// ----
/**
* Constructor
*
* @param is
* InputStram
* @param type
* tipo de flujo (OUTPUT o ERROR)
* @param redirect
* OutputStream donde redireccionar la salida
* @param debug
* indica si se debe mostrar o no la salida por la salida
* estandard
*/
StreamGobbler(InputStream is, String type, OutputStream redirect,
boolean debug) {
this.is = is;
this.type = type;
this.os = redirect;
this.debug = debug;
}
// ----
/**
* Ejecutar el hilo
*/
public void run() {
try {
PrintWriter pw = null;
if (os != null)
pw = new PrintWriter(os);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
// si hay fichero lo imprime a fichero
if (pw != null)
pw.println(line);
if (debug)
System.out.println(type + "> " + line);
output = output + line + "\r\n";
}
if (pw != null)
pw.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
// ------
/**
* Recuperar el flujo de datos generado
*
* @return un String con el output
*/
public String getOutput() {
return output;
}
// ------
}
// end of class StreamGobbler.java

y la clase Script.java:


/**
* Script.java
*
* Clase para ejecutar scripts unix o SQL localmente
*
* @author jdelgado
* @version 0.0.0.1 - 13 Marzo 2007
* @since JDK 1.5 - Eclipse 3.2
*
*/
package comun.util.unix;
import java.io.File;
import java.io.FileOutputStream;
public class Script {
// contenido a ejecutar
private String content = null;
// interprete de comandos: Si usas Windows adaptalo para usar CMD
private String SHELL = "/bin/sh";
// resultado de la ejecucion
private String output = null;
// posibles errores en la ejecucion
private String error = null;
// imprimir o no traza en los threads
private Boolean verbose = false;
// path por defecto para ficheros temporales
private String RUTA = "/tmp";
// cabecera para shell scripts
private String SHELLHEADER = "#!/bin/sh";
// indica si hay que añadir el interprete a los shell scripts que se generen
private boolean addSHELLHEADER = false;
// caracter de retorno
private String RETORNO = "\n";
// ----
/**
* Constructor. crea una nueva instancia de la clase
*/
public Script() {
}
// ----
/**
* Constructor. crea una nueva instancia de la clase
*
* @param content
* contenido del script a ejecutar
*/
public Script(String content) {
this.content = content;
}
// ----
/**
* Ejecuta el script
*
* @throws Exception
* excepcion levantada en caso de error
*/
public String executeCommand() throws Exception {
output = null;
error = null;
StreamGobbler errorGobbler = null;
StreamGobbler outputGobbler = null;
try {
if (content == null)
throw new Exception("command is null");
// String ruta="/home/jose/Desktop/temporal.txt";
// FileOutputStream fos = new FileOutputStream(ruta);
Runtime rt = Runtime.getRuntime();
// Process proc = rt.exec(new String[]{"/bin/sh", "-c", "cd
// /home/jose/Desktop\n./SQLPLUS.sh\ncal\\nps -ef"});
String[] data = new String[3];
data[0] = this.SHELL;
data[1] = "-c";
data[2] = this.content;
Process proc = rt.exec(data);
// any error message?
errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR",
this.verbose);
// any output?
outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT",
null, this.verbose);
// StreamGobbler(proc.getInputStream(), "OUTPUT", fos);
// kick them off
errorGobbler.start();
outputGobbler.start();
// any error???
int exitVal = proc.waitFor();
} catch (Throwable t) {
t.printStackTrace();
} finally {
String out = outputGobbler.getOutput();
this.output = out;
output = out;
out = errorGobbler.getOutput();
this.error = out;
error = out;
}
return output;
}
// ----
/**
* Recupera la salida de la ejecucion del comando
* @return un string con el resultado de la ejecucion
*/
public String getOutput() {
return output;
}
// ----
/**
* Recupera el error de la ejecucion del comando
* @return un string con el error de la ejecucion
*/
public String getError() {
return error;
}
// ----
/**
* Ejecuta un Script creando un fichero .sh con el contenido y ejecutandolo
*
* @param content
* contenido del script
* @param pathname
* el nombre del fichero que se crea si es null lo crea en /tmp y
* de la forma /tmp/timestamp.sh
* @param delete
* indica si se debe borrar o no el fichero temporal tras su
* ejecucion
* @result el resultado de la ejecucion del Script
* @throws Exception
* Excepcion levantada en caso de error
*/
public String executeScript(String content, String pathname, boolean delete)
throws Exception {
File f = null;
FileOutputStream fout = null;
try {
// crear fichero .sh
if (pathname == null) {
long timestamp = System.currentTimeMillis();
pathname = RUTA + File.separator + timestamp + ".sh";
}
if (this.addSHELLHEADER)
{
content = this.SHELLHEADER+this.RETORNO+content;
}
traza("executeScript","Generando fichero [" + pathname + "]...");
f = new File(pathname);
fout = new FileOutputStream(f);
fout.write(content.getBytes());
if (fout != null)
fout.close();
traza("executeScript","Fichero generado");
// darle permisos de ejecucion
traza("executeScript","Asignando permisos...");
Script permisos = new Script("chmod +x " + pathname);
permisos.setVerbose(this.verbose);
permisos.executeCommand();
String error = permisos.getError();
if (error != null) {
if (error.length() > 0)
throw new Exception("Permission denied : " + error);
}
traza("executeScript","Permisos asignados");
// ejecutar fichero .sh
traza("executeScript","Ejecutando script...");
Script ejecucion = new Script(pathname);
ejecucion.setVerbose(this.verbose);
String result = ejecucion.executeCommand();
error = ejecucion.getError();
this.error = error;
this.output = result;
traza("executeScript","Script ejecutado");
// eliminar fichero .sh
if (delete) {
if (f != null) {
if (f.exists())
f.delete();
}
traza("executeScript","fichero eliminado");
}
return result;
} catch (Exception e) {
throw e;
}
}
// ----
/**
* Para probar el correcto funcionamiento de la clase
* @param args argumentos de entrada
*/
public static void main(String[] args) {
try {
// sqlplus directamente no mejor ejecutar sh shellscript.sh que tenga el
// contenido
// Script sc = new Script("ls -l\ncal2\nps -ef | grep
// java\nsqlplus");
// sc.setDebug(false);
// String output = sc.executeCommand();
// System.out.println("OUT:-------------------\r\n"+output);
// String error = sc.getError();
// System.out.println("ERROR:-----------------\r\n"+error);
// output = sc.getOutput();
// System.out.println("output:\r\n"+output);
// System.out.println("***ERROR***");
// String err = sc.getError();
// System.out.println("error:"+err);
Script sc = new Script();
sc.setVerbose(true);
String CONTENT = "sqlplus2\nls -l\nps\necho \"End\\nFin\"";
String OUTPUT = sc.executeScript(CONTENT,
"/home/jose/Desktop/MiScript.sh", true);
System.out.println(OUTPUT);
String ERROR = sc.getError();
System.out.println("**ERROR**" + ERROR);
Script sql = new Script();
sql.setVerbose(false);
sql.setAddSHELLHEADER(true);
sql.setSHELLHEADER("#!/bin/sh");
//sql.setRUTA("/home/jose/Desktop");
CONTENT = "SELECT sysdate FROM DUAL;\nSELECT sysdate FECHA_HOY FROM DUAL;";
OUTPUT = sql.executeSQLScript(CONTENT, "EVO", "EVO", "EVODES",
null, "/home/jose/Desktop/MiSQL.sh", false);
System.out.println(OUTPUT);
ERROR = sql.getError();
System.out.println("**ERROR**" + ERROR);
} catch (Exception e) {
e.printStackTrace();
}
}
// ----
/**
* Completa un script de SQL para poder ejecutarlo con sqlplus desde un
* shell script
*
* @param sqlcontent
* sentencias SQL
* @param user
* usuario de base de datos
* @param password
* password de la base de datos (TODO: guardar encriptada)
* @param sid
* sid de la base de datos
* @param redirect
* si se indica es el fichero donde se redirecciona la salida del
* sqlplus
* @return un string con el sqlplus
*/
public String prepareSQLScript(String sqlcontent, String user,
String password, String sid, String redirect) {
if (redirect == null)
redirect = "";
else
redirect = "> " + redirect;
String INICIO_SQL = "sqlplus " + user + "/" + password + "@" + sid
+ " << EOF" + " " + redirect;
String FIN_SQL = "EOF";
String sql = sqlcontent;
sql = INICIO_SQL + RETORNO + sql + RETORNO + "exit" + RETORNO + FIN_SQL;
return sql;
}
// ----
/**
* Ejecuta un Script SQL mediante sqlplus
*
* @param sqlcontent
* las sentencias SQL
* @param user
* usuario de la base de datos
* @param password
* la password de la base de datos
* @param redirect
* si se indica es el fichero donde se redirecciona la salida del
* sqlplus
* @param pathname
* nombre del shell script que se crea
* @param delete
* indica si se debe borrar o no el shell script tras la
* ejecucion
* @return el resultado de la ejecucion del script
*/
public String executeSQLScript(String sqlcontent, String user,
String password, String sid, String redirect, String pathname,
boolean delete) throws Exception {
String SQL_CONTENT = prepareSQLScript(sqlcontent, user, password, sid,
redirect);
return executeScript(SQL_CONTENT, pathname, delete);
}
// ----
/**
* Recupera el valor del flag
* @return el valor del flag
*/
public Boolean getVerbose() {
return verbose;
}
// ----
/**
* Fija el valor del flag para mostrar por la consola estandard la ejecucion
* @param debug el valor del flag
*/
public void setVerbose(Boolean debug) {
this.verbose = debug;
}
// ----
/**
* Para imprimir un mensaje de traza
*
* @param metodo
* nombre del metodo
* @param mensaje
* nombre de la clase
*/
public void traza(String metodo, String mensaje) {
// TODO: reemplazar aqui para emplear LOG4J
// System.out.println(mensaje);
}
// ----
public boolean isAddSHELLHEADER() {
return addSHELLHEADER;
}
public void setAddSHELLHEADER(boolean addSHELLHEADER) {
this.addSHELLHEADER = addSHELLHEADER;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getRETORNO() {
return RETORNO;
}
public void setRETORNO(String retorno) {
RETORNO = retorno;
}
public String getRUTA() {
return RUTA;
}
public void setRUTA(String ruta) {
RUTA = ruta;
}
public String getSHELL() {
return SHELL;
}
public void setSHELL(String shell) {
SHELL = shell;
}
public String getSHELLHEADER() {
return SHELLHEADER;
}
public void setSHELLHEADER(String shellheader) {
SHELLHEADER = shellheader;
}
public void setError(String error) {
this.error = error;
}
public void setOutput(String output) {
this.output = output;
}
}
// end Script.java

Pueden ser de utilidad cuando queremos automatizar tareas (ejecucion automatica de shell scripts) y no queremos meternos en mucha faena escribiendolos en ANT. Pero bueno, de esto ya hablaremos otro dia…

shell.jpg

Comentarios»

1. max - septiembre 12, 2007

Hola, Gracias por publicar esto esta muy bueno, aunque no es exactamente lo que necesito si me sirve para a partir de esto hacer lo que quiero. y eso es ejecutar scripts desde java pero usando «sudo» suponiendo que el usuario no esta con cuenta de administrador, entonces el sistema le solicitara la clave y necesito lograr que el usuario ingrese su contraseña y java pase esa contraseña al sistema para poder ejecutar el script.

Saludos.

2. javier - octubre 16, 2007

Consulta, Donde guardas la clase que generaste, yo estoy trabajando con un linux y llamo a la case desde un jsp de esta manera:
Pero no lo encuentra, porque creo estoy guardando en un direcotrio incorrecto la clase.

3. superpiwi - octubre 19, 2007

Dime el error que te da e intento ayudarte mejor.
De todas formas estoy trabajando en crear un framework de ejecucion y control de procesos. va a ser la leche xD
cuando lo tenga terminado lo compartire para la comunidad.

4. superpiwi - octubre 19, 2007
5. Andrey - agosto 11, 2009

Pero como hago para iniciar un Telnet, en windos se hace cmd /c start telnet xxx.xxx.xxx.xxx
pero en linux como?
no me funciona lo del start.
hay otro metodo o q?

baiarri - febrero 12, 2010

Runtime rt = Runtime.getRuntime();
String ip =new String(» localhost»);
String port = new String(» 23″);
String comando [] = {«gnome-terminal»,»-e»,»telnet «+ip+port};
rt.exec(comando);

6. tigremiau - abril 14, 2010

Hola Tengo el siguiente comando para ejecutar

lptout.c x0ff (por ejemplo) como lo haria, pues mira lptout.c es una aplicacion en C y quisiera ejecutarlo desde un boton jsp ò de php.

Nota el exec de php no me funciono.

7. luismec - febrero 18, 2011

Hola, disculpa que libreria estas utilizando?

8. Renzo - agosto 1, 2012

Hola, una consulta, te habras topado con algo como esto?

Se requiere de una clase que ejecute un archivo .ctl (que es un como un bat pero para Oracle, claro este ctl tiene comandos para insertar registros a una base de datos oracle) desde java, usando spring e ibatis.

Si te has topado por favor publicalo.

Muchas gracias de antemano.

9. Midasxpm - julio 7, 2013

Thanks, this website is extremely practical.
Regards – midsummer articles – K0nst4ntyn0

10. How To Fix Winrar Error De Lectura En El Fichero in Windows - enero 7, 2015

[…] Ejecutar Shell Scripts desde Java | Java.Lang.NullPointer – Mar 14, 2007 · Y ya que hemos hablado en el Post anterior de Shell Scripts, porque no ejecutarlos directamente desde codigo fuente con Java. Antes de nada recomiendo …… […]

11. mishell - junio 4, 2015

amigo el codigo ta cvr…pero hay un problema como hago para cambiar la ruta de mi pc…por q me vota error …esta es tu ruta(«/home/jose/Desktop/MiSQL.sh»)…pero como hago para cambiarlo al mio…por fa te lo agradeceria…

12. Ariel Papaianni - julio 8, 2015

Muchas gracias por la ayuda. Sos un genio. Excelente trabajo.


Deja un comentario