¿Cómo ejecuto un archivo por lotes desde mi aplicación Java?

107

En mi aplicación Java, quiero ejecutar un archivo por lotes que llame a " scons -Q implicit-deps-changed build\file_load_type export\file_load_type"

Parece que ni siquiera puedo ejecutar mi archivo por lotes. No tengo ideas.

Esto es lo que tengo en Java:

Runtime.
   getRuntime().
   exec("build.bat", null, new File("."));

Anteriormente, tenía un archivo Python Sconscript que quería ejecutar, pero como eso no funcionó, decidí que llamaría al script a través de un archivo por lotes, pero ese método aún no ha tenido éxito.

Amara
fuente

Respuestas:

172

Los archivos por lotes no son ejecutables. Necesitan una aplicación para ejecutarlos (es decir, cmd).

En UNIX, el archivo de secuencia de comandos tiene shebang (#!) Al comienzo de un archivo para especificar el programa que lo ejecuta. El Explorador de Windows realiza doble clic en Windows. CreateProcessno sabe nada de eso.

Runtime.
   getRuntime().
   exec("cmd /c start \"\" build.bat");

Nota: Con el start \"\"comando, se abrirá una ventana de comando separada con un título en blanco y cualquier resultado del archivo por lotes se mostrará allí. También debería funcionar solo con `cmd / c build.bat", en cuyo caso la salida se puede leer desde el subproceso en Java si se desea.

Paulo Guedes
fuente
Para mí, dice que Windows no puede encontrar "build.bat". Entonces, ¿dónde debería poner este archivo? O cómo debo dar el camino. ¿Alguna sugerencia?
nanospeck
1
digamos que tengo una matriz de comandos y luego iterando esa matriz para ejecutar todos los comandos para (i = 0 a commands.length) {Runtime.getRuntime (). exec ("cmd / c start buil.bat"); } luego, para cada iteración (para cada comando), se abre una ventana de comando, lo cual es obvio. ¿Cómo puedo evitar eso? Me refiero a ejecutar todos los comandos en una ventana.
viveksinghggits
1
Tenemos un código que llama directamente a "gradlew.bat" sin poner "cmd / c" delante de él, y ese código está funcionando de alguna manera. Así que supongo que Java o Windows solucionaron parte del problema en algún momento. Si intentamos ejecutar "gradlew", eso falla, así que claramente el ".bat" todavía es necesario al final.
Trejkaz
Win+R(Runtime) puede ejecutar archivos por lotes directamente.
Alex78191
21

A veces, el tiempo del proceso de ejecución del subproceso es mayor que el tiempo del proceso de espera del subproceso de JVM, suele suceder cuando el proceso que está invocando tarda algún tiempo en procesarse, utilice el comando waitFor () de la siguiente manera:

try{    
    Process p = Runtime.getRuntime().exec("file location here, don't forget using / instead of \\ to make it interoperable");
    p.waitFor();

}catch( IOException ex ){
    //Validate the case the file can't be accesed (not enought permissions)

}catch( InterruptedException ex ){
    //Validate the case the process is being stopped by some external situation     

}

De esta manera, la JVM se detendrá hasta que finalice el proceso que está invocando antes de continuar con la pila de ejecución de subprocesos.

Juan Carlos Alpízar
fuente
20
Runtime runtime = Runtime.getRuntime();
try {
    Process p1 = runtime.exec("cmd /c start D:\\temp\\a.bat");
    InputStream is = p1.getInputStream();
    int i = 0;
    while( (i = is.read() ) != -1) {
        System.out.print((char)i);
    }
} catch(IOException ioException) {
    System.out.println(ioException.getMessage() );
}
Isha
fuente
2
Sería útil comentar este código y decirnos por qué y qué está leyendo InputStream, y por qué me importa. Además, el código para el archivo por lotes se está ejecutando bien, pero no puedo hacer que genere una excepción de error.
Baruch Atta
2
Me volvería loco tener un nombre de variable tan confuso como "es" en mi código.
John Fisher
14

Para ejecutar archivos por lotes usando java si eso es lo que estás hablando ...

String path="cmd /c start d:\\sample\\sample.bat";
Runtime rn=Runtime.getRuntime();
Process pr=rn.exec(path);`

Esto debería hacerlo.

Abbia
fuente
10
La pregunta ya fue respondida con una solución funcional. Debe ofrecer solo soluciones que sepa que funcionan y describir por qué cree que su solución podría ser mejor.
Smamatti
12

ProcessBuilder es la forma Java 5/6 de ejecutar procesos externos.

basszero
fuente
2
¿Por qué ProcessBuilder es el camino a seguir en Java 5/6?
Dan Polites
2
Opción interesante para resucitar una publicación antigua ... ProcessBuilder ofrece más control, específicamente la capacidad de redirigir fácilmente stderr a stdout. También encuentro la configuración más intuitiva, pero esa es una
preferencia
10

El ejecutable que se usa para ejecutar scripts por lotes es el cmd.exeque usa la /cbandera para especificar el nombre del archivo por lotes a ejecutar:

Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", "build.bat"});

Teóricamente, también debería poder ejecutar Scons de esta manera, aunque no lo he probado:

Runtime.getRuntime().exec(new String[]{"scons", "-Q", "implicit-deps-changed", "build\file_load_type", "export\file_load_type"});

EDITAR: Amara, dices que esto no está funcionando. El error que enumeró es el error que obtendría al ejecutar Java desde una terminal Cygwin en una caja de Windows; es esto lo que estas haciendo? El problema con eso es que Windows y Cygwin tienen rutas diferentes, por lo que la versión de Windows de Java no encontrará los scons ejecutables en su ruta Cygwin. Puedo explicar más si esto resulta ser su problema.

Eli Courtwright
fuente
Gracias. Todavía no funciona, ese fragmento de código ni siquiera se ejecuta en mi aplicación. Probaré la otra opción que presentó. Gracias de nuevo.
Amara
Cuando intento la segunda alternativa, me da este error: Excepción en el hilo "principal" java.io.IOException: No se puede ejecutar el programa "scons": Error de CreateProcess = 2, El sistema no puede encontrar el archivo especificado
Amara
No, no tengo terminal Cygwin. Yo uso el terminal de comandos de Windows. Es extraño, no sé por qué no funcionaría. Me desconcierta por completo.
Amara
3
Process p = Runtime.getRuntime().exec( 
  new String[]{"cmd", "/C", "orgreg.bat"},
  null, 
  new File("D://TEST//home//libs//"));

probado con jdk1.5 y jdk1.6

Esto funcionó bien para mí, espero que también ayude a otros. para conseguir esto he luchado más días. :(

Suren
fuente
1
agregue esto ==> Lector BufferedReader = new BufferedReader (new InputStreamReader (p.getInputStream ())); Línea de cadena = reader.readLine (); while (línea! = nulo) {System.out.println (línea); línea = reader.readLine (); }
Suren
2

Tuve el mismo problema. Sin embargo, a veces CMD no pudo ejecutar mis archivos. Es por eso que creo un temp.bat en mi escritorio, luego este temp.bat ejecutará mi archivo, y luego el archivo temporal se eliminará.

Sé que este es un código más grande, sin embargo funcionó para mí al 100% cuando incluso Runtime.getRuntime (). Exec () falló.

// creating a string for the Userprofile (either C:\Admin or whatever)
String userprofile = System.getenv("USERPROFILE");

BufferedWriter writer = null;
        try {
            //create a temporary file
            File logFile = new File(userprofile+"\\Desktop\\temp.bat");   
            writer = new BufferedWriter(new FileWriter(logFile));

            // Here comes the lines for the batch file!
            // First line is @echo off
            // Next line is the directory of our file
            // Then we open our file in that directory and exit the cmd
            // To seperate each line, please use \r\n
            writer.write("cd %ProgramFiles(x86)%\\SOME_FOLDER \r\nstart xyz.bat \r\nexit");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // Close the writer regardless of what happens...
                writer.close();
            } catch (Exception e) {
            }

        }

        // running our temp.bat file
        Runtime rt = Runtime.getRuntime();
        try {

            Process pr = rt.exec("cmd /c start \"\" \""+userprofile+"\\Desktop\\temp.bat" );
            pr.getOutputStream().close();
        } catch (IOException ex) {
            Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);

        }
        // deleting our temp file
        File databl = new File(userprofile+"\\Desktop\\temp.bat");
        databl.delete();
Ben Jost
fuente
1

Lo siguiente funciona bien:

String path="cmd /c start d:\\sample\\sample.bat";
Runtime rn=Runtime.getRuntime();
Process pr=rn.exec(path);
bharat
fuente
¿Qué significa la / c?
Amal lal TL
0

Este código ejecutará dos comandos.bat que existen en la ruta C: / carpetas / carpeta.

Runtime.getRuntime().exec("cd C:/folders/folder & call commands.bat");
رامي عبد الله
fuente
0

Para ampliar la respuesta de @ Isha, puede hacer lo siguiente para obtener el resultado devuelto (post-facto, no en tiempo real) del script que se ejecutó:

try {
    Process process = Runtime.getRuntime().exec("cmd /c start D:\\temp\\a.bat");
    System.out.println(process.getText());
} catch(IOException e) {
    e.printStackTrace();
}
NoodleOfDeath
fuente