2009-02-08 23 views
119

Es bastante simple ejecutar un comando de Unix desde Java.¿Cómo ejecutar un script de shell Unix desde código Java?

Runtime.getRuntime().exec(myCommand); 

¿Pero es posible ejecutar un script de shell Unix desde el código de Java? En caso afirmativo, ¿sería una buena práctica ejecutar un script de shell desde el código de Java?

+3

Las cosas se ponen interesantes si ese script de shell es interactivo. – ernesto

+0

¿Cuál es la variable myCommand de esa cadena?si es así, entonces no funcionará, el método exec requiere String [] y argumento, ver debajo de mi answar, funciona perfectamente –

+0

http://stackoverflow.com/questions/525212/how-to-run-unix-shell-script -from-java-code/37327025 # 37327025 –

Respuesta

21

creo que haya respondido a su propia pregunta con

Runtime.getRuntime().exec(myShellScript); 

En cuanto a si es una buena práctica ... ¿qué estás tratando de hacer con un script de shell que no se puede hacer con Java?

+0

Me he enfrentado a una situación similar en la que necesito sincronizar algunos archivos en diferentes servidores cuando ocurre una determinada condición en mi código de Java. ¿Hay alguna otra forma mejor? –

23

Yo diría que no es en el espíritu de Java para ejecutar un script de shell de Java. Java pretende ser multiplataforma, y ​​ejecutar un script de shell limitaría su uso a solo UNIX.

Dicho esto, definitivamente es posible ejecutar un script de shell desde Java. Usarías exactamente la misma sintaxis que enumeró (no lo intenté yo mismo, pero intente ejecutar el script de shell directamente, y si eso no funciona, ejecuta el propio shell, pasando el script como un parámetro de línea de comando) .

+37

Sí, pero en muchos sentidos el mantra "espíritu de Java" o "escribir una vez en todas partes" es un mito de todos modos. – BobbyShaftoe

+12

¿Qué tiene de mítico? –

+6

"escribir una vez en todas partes" depende del programador ... – Spider

1

Es posible, solo ejecútelo como cualquier otro programa. ¡Solo asegúrate de que tu script tenga el # correcto! (she-bang) línea como la primera línea del script, y asegúrese de que haya permisos de ejecución en el archivo.

Por ejemplo, si se trata de un script bash, coloca #!/Bin/bash en la parte superior del script, también chmod + x.

También en cuanto a si es una buena práctica, no lo es, especialmente para Java, pero si te ahorra mucho tiempo al portar un gran script, y no te pagan extra para hacerlo;) guarda tu tiempo, ejecute la secuencia de comandos y coloque la migración a Java en su lista de tareas pendientes a largo plazo.

153

Realmente debería mirar Process Builder. Está realmente construido para este tipo de cosas.

ProcessBuilder pb = new ProcessBuilder("myshellScript.sh", "myArg1", "myArg2"); 
Map<String, String> env = pb.environment(); 
env.put("VAR1", "myValue"); 
env.remove("OTHERVAR"); 
env.put("VAR2", env.get("VAR1") + "suffix"); 
pb.directory(new File("myDir")); 
Process p = pb.start(); 
+0

¿Es una buena práctica llamar a los scripts de JAVA? Cualquier problema de rendimiento? – kautuksahni

+0

Tenga en cuenta que puede necesitar especificar el programa/bin/bash o sh para ejecutar el script dentro dependiendo de la configuración de Java (consulte https://stackoverflow.com/questions/25647806/running-shell-script-from-external- directory-no-such-file-or-directory) –

0

Justo lo mismo que Solaris 5.10 funciona de la siguiente ./batchstart.sh hay un truco que no sé si su sistema operativo acepta usar \\. batchstart.sh lugar. Esta barra doble puede ayudar.

2

En cuanto a mí, todas las cosas deben ser simples. Para ejecutar el script sólo tiene que ejecutar

new ProcessBuilder("pathToYourShellScript").start(); 
8

Sí, es posible hacerlo. Esto funcionó para mí.

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 

import org.omg.CORBA.portable.InputStream; 

public static void readBashScript() { 
     try { 
      Process proc = Runtime.getRuntime().exec("/home/destino/workspace/JavaProject/listing.sh /"); //Whatever you want to execute 
      BufferedReader read = new BufferedReader(new InputStreamReader(
        proc.getInputStream())); 
      try { 
       proc.waitFor(); 
      } catch (InterruptedException e) { 
       System.out.println(e.getMessage()); 
      } 
      while (read.ready()) { 
       System.out.println(read.readLine()); 
      } 
     } catch (IOException e) { 
      System.out.println(e.getMessage()); 
     } 
    } 
0

Creo que con

System.getProperty("os.name"); 

Comprobación del sistema operativo en puede administrar el scrips shell/bash si tales son compatibles. si es necesario hacer que el código sea portátil.

16

También puede usar Apache Commons exec library.

Ejemplo:

package testShellScript; 

import java.io.IOException; 
import org.apache.commons.exec.CommandLine; 
import org.apache.commons.exec.DefaultExecutor; 
import org.apache.commons.exec.ExecuteException; 

public class TestScript { 
    int iExitValue; 
    String sCommandString; 

    public void runScript(String command){ 
     sCommandString = command; 
     CommandLine oCmdLine = CommandLine.parse(sCommandString); 
     DefaultExecutor oDefaultExecutor = new DefaultExecutor(); 
     oDefaultExecutor.setExitValue(0); 
     try { 
      iExitValue = oDefaultExecutor.execute(oCmdLine); 
     } catch (ExecuteException e) { 
      System.err.println("Execution failed."); 
      e.printStackTrace(); 
     } catch (IOException e) { 
      System.err.println("permission denied."); 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String args[]){ 
     TestScript testScript = new TestScript(); 
     testScript.runScript("sh /root/Desktop/testScript.sh"); 
    } 
} 

Para mayor referencia, se da un ejemplo en Apache Doc también.

+0

¿Puedo ejecutar esto en Windows? – bekur

+0

@KisHanSarsecHaGajjar también podemos capturar el resultado de shellscript y mostrarlo en el ui de Java. Quiero saber si es posible hacerlo –

+0

@KranthiSama Puede establecer 'OutputStream' para' DefaultExecuter' utilizando el método 'DefaultExecuter.setStreamHandler' para capturar la salida en' OutputStream'. Consulte este hilo para obtener más información: [¿Cómo puedo capturar la salida de un comando ...] (http://stackoverflow.com/a/6295923/1686291) –

1
String scriptName = PATH+"/myScript.sh"; 
    String commands[] = new String[]{scriptName,"myArg1", "myArg2"}; 

    Runtime rt = Runtime.getRuntime(); 
    Process process = null; 
    try{ 
     process = rt.exec(commands); 
     process.waitFor(); 
    }catch(Exception e){ 
     e.printStackTrace(); 
    } 
2

Aquí está mi ejemplo. Espero que tenga sentido.

public static void excuteCommand(String filePath) throws IOException{ 
    File file = new File(filePath); 
    if(!file.isFile()){ 
     throw new IllegalArgumentException("The file " + filePath + " does not exist"); 
    } 
    if(this.isLinux()){ 
     Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", filePath}, null); 
    }else if(this.isWindows()){ 
     Runtime.getRuntime().exec("cmd /c start " + filePath); 
    } 
} 
public static boolean isLinux(){ 
    String os = System.getProperty("os.name"); 
    return os.toLowerCase().indexOf("linux") >= 0; 
} 

public static boolean isWindows(){ 
    String os = System.getProperty("os.name"); 
    return os.toLowerCase().indexOf("windows") >= 0; 
} 
2

La biblioteca ZT Process Executor es una alternativa a Apache Commons Exec. Tiene funcionalidad para ejecutar comandos, capturar su salida, establecer tiempos de espera, etc.

No lo he usado todavía, pero parece razonablemente bien documentado.

Un ejemplo de la documentación: Ejecutar un comando, bombear el stderr a un registrador, devolver la salida como cadena UTF8.

String output = new ProcessExecutor().command("java", "-version") 
    .redirectError(Slf4jStream.of(getClass()).asInfo()) 
    .readOutput(true).execute() 
    .outputUTF8(); 

Su documentación se enumeran las siguientes ventajas sobre Commons Exec:

  • mejorando la gestión de los flujos
    • de lectura/escritura a los arroyos
    • Redirección stderr a stdout
  • Manejo mejorado de tiempos de espera
  • Mejora de la verificación de los códigos de salida
  • mejoradas API
    • trazadores de líneas uno para los casos de uso bastante complejos
    • trazadores de líneas uno para conseguir la salida del proceso en una cadena
    • El acceso a la objeto Proceso disponibles
    • Soporte para procesos asíncronos (Futuro)
  • Mejora de la tala con SLF4J API
  • Soporte para múltiples procesos
2

Sí, es posible y que haya respondido a ella! Sobre buenas prácticas, creo que es mejor lanzar comandos desde archivos y no directamente desde su código. Por lo tanto, debe hacer que Java ejecute la lista de comandos (o un comando) en un archivo .bat, .sh, .ksh ... existente. Aquí es un ejemplo de la ejecución de una lista de comandos en un archivo "MyFile.sh":

String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"}; 
    Runtime.getRuntime().exec(cmd); 
2

Para evitar tener que codificar una ruta absoluta, puede utilizar el siguiente método que va a encontrar y ejecutar la secuencia de comandos si está en tu directorio raíz.

public static void runScript() throws IOException, InterruptedException { 
    ProcessBuilder processBuilder = new ProcessBuilder("./nameOfScript.sh"); 
    //Sets the source and destination for subprocess standard I/O to be the same as those of the current Java process. 
    processBuilder.inheritIO(); 
    Process process = processBuilder.start(); 

    int exitValue = process.waitFor(); 
    if (exitValue != 0) { 
     // check for errors 
     new BufferedInputStream(process.getErrorStream()); 
     throw new RuntimeException("execution of script failed!"); 
    } 
} 
Cuestiones relacionadas