Ejecuci贸n de comandos de shell con Java

    Introducci贸n

    En este art铆culo, veremos c贸mo podemos aprovechar la Runtime y ProcessBuilder clases para ejecutar comandos de shell y scripts con Java.

    Usamos computadoras para automatizar muchas cosas en nuestro trabajo diario. Los administradores del sistema ejecutan muchos comandos todo el tiempo, algunos de los cuales son muy repetitivos y requieren cambios m铆nimos entre ejecuciones.

    Este proceso tambi茅n est谩 listo para la automatizaci贸n. No es necesario ejecutar todo manualmente. Usando Java, podemos ejecutar comandos de shell 煤nicos o m煤ltiples, ejecutar scripts de shell, ejecutar la terminal / s铆mbolo del sistema, establecer directorios de trabajo y manipular variables de entorno a trav茅s de clases centrales.

    Runtime.exec ()

    los Runtime class en Java es una clase de alto nivel, presente en cada una de las aplicaciones Java. A trav茅s de 茅l, la propia aplicaci贸n se comunica con el entorno en el que se encuentra.

    Extrayendo el tiempo de ejecuci贸n asociado con nuestra aplicaci贸n a trav茅s del getRuntime() m茅todo, podemos utilizar el exec() m茅todo para ejecutar comandos directamente o ejecutar .bat/.sh archivos.

    los exec() El m茅todo ofrece algunas variaciones sobrecargadas:

    • public Process exec(String command) – Ejecuta el comando contenido en command en un proceso separado.
    • public Process exec(String command, String[] envp) – Ejecuta el command, con una serie de variables de entorno. Se proporcionan como una matriz de cadenas, siguiendo el name=value formato.
    • public Process exec(String command, String[] envp, File dir) – Ejecuta el command, con las variables de entorno especificadas, desde dentro del dir directorio.
    • public Process exec(String cmdArray[]) – Ejecuta un comando en forma de una matriz de cadenas.
    • public Process exec(String cmdArray[], String[] envp) – Ejecuta un comando con las variables de entorno especificadas.
    • public Process exec(String cmdarray[], String[] envp, File dir) – Ejecuta un comando, con las variables de entorno especificadas, desde dentro del dir directorio.

    Vale la pena se帽alar que estos procesos se ejecutan externamente desde el int茅rprete y depender谩n del sistema.

    Lo que tambi茅n vale la pena se帽alar es la diferencia entre String command y String cmdArray[]. Logran lo mismo. UN command se divide en una matriz de todos modos, por lo que el uso de cualquiera de estos dos deber铆a producir los mismos resultados.

    Depende de usted decidir si exec("dir /folder") o exec(new String[]{"dir", "/folder"} es lo que le gustar铆a usar.

    Escribamos algunos ejemplos para ver c贸mo estos m茅todos sobrecargados se diferencian entre s铆.

    Ejecutando un comando desde una cadena

    Comencemos con el enfoque m谩s simple de estos tres:

    Process process = Runtime.getRuntime().exec("ping www.Pharos.sh.com");
    

    Al ejecutar este c贸digo, se ejecutar谩 el comando que hemos proporcionado en formato String. Sin embargo, no vemos nada cuando ejecutamos esto.

    Para validar si esto se ejecut贸 correctamente, querremos obtener el process objeto. Usemos un BufferedReader para ver lo que est谩 pasando:

    public static void printResults(Process process) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line = "";
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    }
    

    Ahora, cuando ejecutamos este m茅todo despu茅s de exec() m茅todo, deber铆a producir algo similar a:

    Pinging www.Pharos.sh.com [104.18.57.23] with 32 bytes of data:
    Reply from 104.18.57.23: bytes=32 time=21ms TTL=56
    Reply from 104.18.57.23: bytes=32 time=21ms TTL=56
    Reply from 104.18.57.23: bytes=32 time=21ms TTL=56
    Reply from 104.18.57.23: bytes=32 time=21ms TTL=56
    
    Ping statistics for 104.18.57.23:
        Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
    Approximate round trip times in milli-seconds:
        Minimum = 21ms, Maximum = 21ms, Average = 21ms
    

    Tenga en cuenta que tendremos que extraer la informaci贸n del proceso del Process instancias a medida que avanzamos en otros ejemplos.

    Especificar el directorio de trabajo

    Si desea ejecutar un comando desde, digamos, una carpeta determinada, har铆amos algo como:

    Process process = Runtime.getRuntime()
            .exec("cmd /c dir", null, new File("C:\Users\"));
          //.exec("sh -c ls", null, new File("Pathname")); for non-Windows users
    printResults(process);
    

    Aqu铆, hemos proporcionado el exec() m茅todo con un command, un null para nuevas variables de entorno y un new File() que se establece como nuestro directorio de trabajo.

    La suma de cmd /c antes de un comando como dir es digno de menci贸n.

    Como estoy trabajando en Windows, esto abre el cmd y /c realiza el comando siguiente. En este caso, es dir.

    La raz贸n por la que esto no era obligatorio para el ping ejemplo, pero es obligatorio para este ejemplo es agradable contestada por un usuario SO.

    Ejecutar el fragmento de c贸digo anterior resultar谩 en:

    Volume in drive C has no label.
     Volume Serial Number is XXXX-XXXX
    
     Directory of C:Users
    
    08/29/2019  05:01 PM    <DIR>          .
    08/29/2019  05:01 PM    <DIR>          ..
    08/18/2016  09:11 PM    <DIR>          Default.migrated
    08/29/2019  05:01 PM    <DIR>          Public
    05/15/2020  11:08 AM    <DIR>          User
                   0 File(s)              0 bytes
                   5 Dir(s)  212,555,214,848 bytes free
    

    Echemos un vistazo a c贸mo podr铆amos suministrar el comando anterior en varias partes individuales, en lugar de una sola cadena:

    Process process = Runtime.getRuntime().exec(
            new String[]{"cmd", "/c", "dir"},
            null, 
            new File("C:\Users\"));
            
    printResults(process);
    

    Ejecutar este fragmento de c贸digo tambi茅n resultar谩 en:

    Volume in drive C has no label.
     Volume Serial Number is XXXX-XXXX
    
     Directory of C:Users
    
    08/29/2019  05:01 PM    <DIR>          .
    08/29/2019  05:01 PM    <DIR>          ..
    08/18/2016  09:11 PM    <DIR>          Default.migrated
    08/29/2019  05:01 PM    <DIR>          Public
    05/15/2020  11:08 AM    <DIR>          User
                   0 File(s)              0 bytes
                   5 Dir(s)  212,542,808,064 bytes free
    

    En 煤ltima instancia, independientemente del enfoque, utilizando una sola cadena o una matriz de cadenas, el comando que ingrese siempre se dividir谩 en una matriz antes de ser procesado por la l贸gica subyacente.

    Cu谩l le gustar铆a usar se reduce a cu谩l le resulta m谩s legible.

    Usar variables de entorno

    Echemos un vistazo a c贸mo podemos usar las variables de entorno:

    Process process = Runtime.getRuntime().exec(
            "cmd /c echo %var1%",
            new String[]{"var1=value1"});
            
    printResults(process);
    

    Podemos proporcionar tantas variables de entorno como queramos dentro de la matriz de cadenas. Aqu铆, acabamos de imprimir el valor de var1 utilizando echo.

    Ejecutar este c贸digo devolver谩:

    value1
    

    Ejecuci贸n de archivos .bat y .sh

    A veces, es mucho m谩s f谩cil descargar todo en un archivo y ejecutar ese archivo en lugar de agregarlo todo mediante programaci贸n.

    Dependiendo de su sistema operativo, usar铆a .bat o .sh archivos. Creemos uno con los contenidos:

    echo Hello World
    

    Entonces, usemos el mismo enfoque que antes:

    Process process = Runtime.getRuntime().exec(
            "cmd /c start file.bat",
            null,
            new File("C:\Users\User\Desktop\"));
    

    Esto abrir谩 el s铆mbolo del sistema y ejecutar谩 el .bat archivo en el directorio de trabajo que hemos establecido.

    Ejecutar este c贸digo seguramente da como resultado:

    Con todos los sobrecargados exec() firmas cuidadas, echemos un vistazo a las ProcessBuilder class y c贸mo podemos ejecutar comandos us谩ndola.

    ProcessBuilder

    ProcessBuilder es el mecanismo subyacente que ejecuta los comandos cuando usamos el Runtime.getRuntime().exec() m茅todo:

    /**
     * Executes the specified command and arguments in a separate process with
     * the specified environment and working directory.
     *...
    */
    public Process exec(String[] cmdarray, String[] envp, File dir) throws IOException {
        return new ProcessBuilder(cmdarray)
            .environment(envp)
            .directory(dir)
            .start();
    }
    

    JavaDocs para Runtime clase

    Echando un vistazo a c贸mo ProcessBuilder toma nuestra opini贸n del exec() y ejecuta el comando, tambi茅n nos da una buena idea de c贸mo usarlo.

    Acepta un String[] cmdarray, y eso es suficiente para que funcione. Alternativamente, podemos proporcionarle argumentos opcionales como el String[] envp y File dir.

    Exploremos estas opciones.

    ProcessBuilder: Ejecutando comando desde cadenas

    En lugar de poder proporcionar una sola cadena, como cmd /c dir, tendremos que dividirlo en este caso. Por ejemplo, si quisi茅ramos enumerar los archivos en el C:/Users directorio como antes, har铆amos:

    ProcessBuilder processBuilder = new ProcessBuilder();
    processBuilder.command("cmd", "/c", "dir C:\Users");
    
    Process process = processBuilder.start();
    printResults(process);
    

    Para ejecutar realmente un Process, ejecutamos el start() comando y asigne el valor devuelto a un Process ejemplo.

    Ejecutar este c贸digo producir谩:

     Volume in drive C has no label.
     Volume Serial Number is XXXX-XXXX
    
     Directory of C:Users
    
    08/29/2019  05:01 PM    <DIR>          .
    08/29/2019  05:01 PM    <DIR>          ..
    08/18/2016  09:11 PM    <DIR>          Default.migrated
    08/29/2019  05:01 PM    <DIR>          Public
    05/15/2020  11:08 AM    <DIR>          User
                   0 File(s)              0 bytes
                   5 Dir(s)  212,517,294,080 bytes free
    

    Sin embargo, este enfoque no es mejor que el anterior. 驴Qu茅 es 煤til con el ProcessBuilder clase es que es personalizable. Podemos configurar las cosas mediante programaci贸n, no solo a trav茅s de comandos.

    ProcessBuilder: especifique el directorio de trabajo

    En lugar de proporcionar el directorio de trabajo a trav茅s del comando, configur茅moslo program谩ticamente:

    processBuilder.command("cmd", "/c", "dir").directory(new File("C:\Users\"));
    

    Aqu铆, hemos configurado el directorio de trabajo para que sea el mismo que antes, pero hemos sacado esa definici贸n del comando en s铆. La ejecuci贸n de este c贸digo proporcionar谩 el mismo resultado que el 煤ltimo ejemplo.

    ProcessBuilder: Variables de entorno

    Utilizando ProcessBuilders, es f谩cil recuperar una lista de variables de entorno en forma de Map. Tambi茅n es f谩cil establecer variables de entorno para que su programa pueda usarlas.

    Consigamos las variables de entorno disponibles actualmente y luego agreguemos algunas para su uso posterior:

    ProcessBuilder processBuilder = new ProcessBuilder();
    
    Map<String, String> environmentVariables  = processBuilder.environment();
    environmentVariables.forEach((key, value) -> System.out.println(key + value));
    

    Aqu铆, hemos empaquetado las variables de entorno devueltas en un Map y corr铆 un forEach() en 茅l para imprimir los valores en nuestra consola.

    La ejecuci贸n de este c贸digo producir谩 una lista de las variables de entorno que tiene en su m谩quina:

    DriverDataC:WindowsSystem32DriversDriverData
    HerokuPathE:Heroku
    ProgramDataC:ProgramData
    ...
    

    Ahora, agreguemos una variable de entorno a esa lista y us茅mosla:

    environmentVariables.put("var1", "value1");
    
    processBuilder.command("cmd", "/c", "echo", "%var1%");
    Process process = processBuilder.start();
    printResults(process);
    

    Ejecutar este c贸digo producir谩:

    value1
    

    Por supuesto, una vez que el programa haya terminado de ejecutarse, esta variable no permanecer谩 en la lista.

    ProcessBuilder: Ejecuci贸n de archivos .bat y .sh

    Si desea ejecutar un archivo, nuevamente, solo proporcionaremos el ProcessBuilder instancia con la informaci贸n requerida:

    processBuilder
            .command("cmd", "/c", "start", "file.bat")
            .directory(new File("C:\Users\User\Desktop"));
    Process process = processBuilder.start();
    

    Al ejecutar este c贸digo, el s铆mbolo del sistema se abre y ejecuta el .bat archivo:

    Conclusi贸n

    En este art铆culo, hemos explorado ejemplos de ejecuci贸n de comandos de shell en Java. Hemos utilizado el Runtime y ProcessBuilder clases para hacer esto.

    Usando Java, podemos ejecutar comandos de shell 煤nicos o m煤ltiples, ejecutar scripts de shell, ejecutar la terminal / s铆mbolo del sistema, establecer directorios de trabajo y manipular variables de entorno a trav茅s de clases centrales.

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *