Te doy la bienvenida a nuestra comunidad, en este lugar hallarás la solucíon que buscabas.
Solución:
Las diversas sobrecargas de Runtime.getRuntime().exec(...)
tomar ya sea un array de cuerdas o una sola string. El soltero-string sobrecargas de exec()
tokenizará el string en una array de argumentos, antes de pasar el string array sobre uno de los exec()
sobrecargas que toma un string array. El ProcessBuilder
los constructores, por otro lado, solo toman un varargs array de cuerdas o un List
de cuerdas, donde cada string en el array o lista se supone que es un argumento individual. De cualquier manera, los argumentos obtenidos se unen en un string que se pasa al sistema operativo para ejecutar.
Entonces, por ejemplo, en Windows,
Runtime.getRuntime().exec("C:DoStuff.exe -arg1 -arg2");
ejecutará un DoStuff.exe
programa con los dos argumentos dados. En este caso, la línea de comandos se tokeniza y se vuelve a armar. Sin embargo,
ProcessBuilder b = new ProcessBuilder("C:DoStuff.exe -arg1 -arg2");
fallará, a menos que haya un programa cuyo nombre sea DoStuff.exe -arg1 -arg2
en C:
. Esto se debe a que no hay tokenización: se supone que el comando para ejecutar ya ha sido tokenizado. En su lugar, debe utilizar
ProcessBuilder b = new ProcessBuilder("C:DoStuff.exe", "-arg1", "-arg2");
o alternativamente
List params = java.util.Arrays.asList("C:DoStuff.exe", "-arg1", "-arg2");
ProcessBuilder b = new ProcessBuilder(params);
mira como Runtime.getRuntime().exec()
pasa el comando String al ProcessBuilder
. Utiliza un tokenizador y explota el comando en tokens individuales, luego invoca exec(String[] cmdarray, ......)
que construye un ProcessBuilder
.
Si construyes el ProcessBuilder
con un array de cadenas en lugar de una sola, obtendrá el mismo resultado.
El ProcessBuilder
constructor toma un String...
vararg, por lo que pasar el comando completo como una sola cadena tiene el mismo efecto que invocar ese comando entre comillas en una terminal:
shell$ "command with args"
No hay diferencia entre ProcessBuilder.start()
y Runtime.exec()
porque la implementación de Runtime.exec()
es:
public Process exec(String command) throws IOException
return exec(command, null, null);
public Process exec(String command, String[] envp, File dir)
throws IOException
if (command.length() == 0)
throw new IllegalArgumentException("Empty command");
StringTokenizer st = new StringTokenizer(command);
String[] cmdarray = new String[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++)
cmdarray[i] = st.nextToken();
return exec(cmdarray, envp, dir);
public Process exec(String[] cmdarray, String[] envp, File dir)
throws IOException
return new ProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
Así que código:
List list = new ArrayList<>();
new StringTokenizer(command)
.asIterator()
.forEachRemaining(str -> list.add((String) str));
new ProcessBuilder(String[])list.toArray())
.environment(envp)
.directory(dir)
.start();
debe ser igual a:
Runtime.exec(command)
Gracias dave_thompson_085 para comentarios