Próbuję wykonać zewnętrzne polecenie z kodu Java, ale zauważyłem różnicę między Runtime.getRuntime().exec(...)
i new ProcessBuilder(...).start()
.
Podczas używania Runtime
:
Process p = Runtime.getRuntime().exec(installation_path +
uninstall_path +
uninstall_command +
uninstall_arguments);
p.waitFor();
wartość exitValue wynosi 0, a polecenie zostało zakończone poprawnie.
Jednak z ProcessBuilder
:
Process p = (new ProcessBuilder(installation_path +
uninstall_path +
uninstall_command,
uninstall_arguments)).start();
p.waitFor();
wartość wyjścia to 1001, a polecenie kończy się w środku, chociaż waitFor
zwraca.
Co mam zrobić, aby rozwiązać problem ProcessBuilder
?
cmd.exe
.Zobacz, jak
Runtime.getRuntime().exec()
przekazuje polecenie String doProcessBuilder
. Używa tokenizera i rozbija polecenie na pojedyncze tokeny, a następnie wywołuje,exec(String[] cmdarray, ......)
który konstruuje plikProcessBuilder
.Jeśli skonstruujesz
ProcessBuilder
tablicę ciągów zamiast jednego, uzyskasz ten sam wynik.ProcessBuilder
Konstruktor bierzeString...
vararg, więc przechodząc całą komendę jako pojedynczy ciąg ma taki sam efekt jak wywoływanie tego polecenia w cudzysłów w terminalu:źródło
Nie ma różnicy między
ProcessBuilder.start()
i,Runtime.exec()
ponieważ implementacjaRuntime.exec()
to:Więc kod:
powinno być takie samo jak:
Dzięki dave_thompson_085 za komentarz
źródło
public Process exec(String command, String[] envp, File dir)
-String
NOTString[]
- które wywołujeStringTokenizer
i umieszcza tokeny w tablicy, która jest następnie przekazywana (pośrednio) doProcessBuilder
, co JEST różnicą, jak poprawnie stwierdzono w trzech odpowiedziach sprzed 7 lat.Tak, jest różnica.
Runtime.exec(String)
Metoda przyjmuje pojedynczy łańcuch dowodzenia, że dzieli się na komendzie i sekwencja argumentów.ProcessBuilder
Konstruktor bierze (varargs) szereg strun. Pierwszy ciąg to nazwa polecenia, a pozostałe to argumenty. (Istnieje alternatywny konstruktor, który pobiera listę ciągów, ale żaden z nich nie przyjmuje pojedynczego ciągu składającego się z polecenia i argumentów).To, co każesz ProcessBuilderowi zrobić, to wykonanie „polecenia”, którego nazwa zawiera spacje i inne śmieci. Oczywiście system operacyjny nie może znaleźć polecenia o tej nazwie, a jego wykonanie kończy się niepowodzeniem.
źródło
Runtime.exec(cmd)
jest efektywnym skrótem doRuntime.exec(cmd.split("\\s+"))
.ProcessBuilder
Klasa nie posiada konstruktora, który jest bezpośrednim odpowiednikiemRuntime.exec(cmd)
. O to właśnie chodzi w mojej odpowiedzi.new ProcessBuilder("command arg1 arg2")
Thestart()
wezwanie nie będzie robić to, czego oczekują. Prawdopodobnie zakończy się niepowodzeniem i powiedzie się tylko wtedy, gdy masz polecenie ze spacjami w nazwie. Właśnie o to pyta PO!