Ich versuche, einen externen Befehl aus Java-Code auszuführen, aber es gibt einen Unterschied zwischen Runtime.getRuntime().exec(...)
und new ProcessBuilder(...).start()
.
Bei Verwendung von Runtime
:
Process p = Runtime.getRuntime().exec(installation_path +
uninstall_path +
uninstall_command +
uninstall_arguments);
p.waitFor();
Der exitValue ist 0 und der Befehl wird ok beendet.
Mit ProcessBuilder
:
Process p = (new ProcessBuilder(installation_path +
uninstall_path +
uninstall_command,
uninstall_arguments)).start();
p.waitFor();
Der Exit-Wert ist 1001 und der Befehl endet in der Mitte, obwohl er waitFor
zurückkehrt.
Was soll ich tun, um das Problem zu beheben ProcessBuilder
?
cmd.exe
.Sehen Sie sich an, wie
Runtime.getRuntime().exec()
der String-Befehl an das übergeben wirdProcessBuilder
. Es verwendet einen Tokenizer und zerlegt den Befehl in einzelne Token. Anschließend wird aufgerufen,exec(String[] cmdarray, ......)
welches a erstellt wirdProcessBuilder
.Wenn Sie die
ProcessBuilder
mit einem Array von Zeichenfolgen anstelle einer einzelnen erstellen, erhalten Sie das gleiche Ergebnis.Der
ProcessBuilder
Konstruktor nimmt einString...
vararg an. Die Übergabe des gesamten Befehls als einzelne Zeichenfolge hat also den gleichen Effekt wie das Aufrufen dieses Befehls in Anführungszeichen in einem Terminal:quelle
Es gibt keinen Unterschied zwischen
ProcessBuilder.start()
undRuntime.exec()
weil die Implementierung vonRuntime.exec()
:Also Code:
sollte das gleiche sein wie:
Danke dave_thompson_085 für den Kommentar
quelle
public Process exec(String command, String[] envp, File dir)
-String
NICHTString[]
- auf, wasStringTokenizer
die Token aufruft und in ein Array legt, an das sie dann (indirekt) übergebenProcessBuilder
werden. Dies ist ein Unterschied, wie in den drei Antworten von vor 7 Jahren korrekt angegeben.Ja, da gibt es einen Unterschied.
Die
Runtime.exec(String)
Methode verwendet eine einzelne Befehlszeichenfolge, die in einen Befehl und eine Folge von Argumenten aufgeteilt wird.Der
ProcessBuilder
Konstruktor verwendet ein (varargs) Array von Zeichenfolgen. Die erste Zeichenfolge ist der Befehlsname und der Rest sind die Argumente. (Es gibt einen alternativen Konstruktor, der eine Liste von Zeichenfolgen verwendet, aber keinen, der eine einzelne Zeichenfolge enthält, die aus dem Befehl und den Argumenten besteht.)Sie fordern ProcessBuilder also auf, einen "Befehl" auszuführen, dessen Name Leerzeichen und anderen Müll enthält. Natürlich kann das Betriebssystem keinen Befehl mit diesem Namen finden und die Befehlsausführung schlägt fehl.
quelle
Runtime.exec(cmd)
ist effektiv eine Abkürzung fürRuntime.exec(cmd.split("\\s+"))
. DieProcessBuilder
Klasse hat keinen Konstruktor, der direkt äquivalent zu istRuntime.exec(cmd)
. Dies ist der Punkt, den ich in meiner Antwort anspreche.new ProcessBuilder("command arg1 arg2")
Derstart()
Aufruf wird nicht das tun, was Sie erwarten. Es wird wahrscheinlich fehlschlagen und nur erfolgreich sein, wenn Sie einen Befehl mit Leerzeichen im Namen haben. Dies ist genau das Problem, nach dem das OP fragt!