我需要使用 java.lang.ProcessBuilder 將使用“sudo”和“su”的不同 sh 命令從我的 java 應用程序傳遞到 Linux。這些命令非常相似,但有些有效,有些無效。當我從日志中復制粘貼命令時,所有命令都有效。在這之后:processBuilder = new ProcessBuilder("sudo", "su", "- USER66 -c", "'ssh remote.mycomp.org < " + workingDir + "/script_cluster.sh'");我有 :su : option invalide -- ' 'Usage: (...)但這一個:processBuilder = new ProcessBuilder("sudo", "su", "- USER66 -c", "'scp remote.mycomp.org:" + clusterWorkingDir + "/" + filename + " " + workingDir + "/resultat/" + dir + "/'");工作完美。正如我之前所說,如果我從日志中復制第一個命令,它就會在沒有任何警告的情況下運行。記錄代碼: logCommand(processBuilder); private void logCommand(ProcessBuilder processBuilder) { if (logger.isDebugEnabled()) { logger.debug("Commande : {}", commandAsString(processBuilder.command())); } } private String commandAsString(List<String> command) { StringBuilder result = new StringBuilder(); for (String cmdElement : command) { result.append(cmdElement).append(" "); } return result.toString(); }我在這里缺少什么?我還能做些什么來了解正在發生的事情?
2 回答

哈士奇WWW
TA貢獻1799條經驗 獲得超6個贊
好吧,我找到了一個令人驚訝的方法來解決這個問題:
訣竅不是分割參數,而是使用“bash -c”重新組合它們:
processBuilder = new ProcessBuilder("bash", "-c", "sudo su - USER66 -c 'ssh remote.mycomp.org < " + workingDir + "/script_cluster.sh'");
請注意,這是多么不直觀,因為沒有人會在 shell 中這樣編寫它,并且使用正確的嵌套轉義將其轉換為 shell 命令可能會變得非常困難。另外,如果將 3 個命令用空格連接起來,也不會形成有效的命令。

慕尼黑的夜晚無繁華
TA貢獻1864條經驗 獲得超6個贊
ProcessBuilder 構造函數需要為每個參數提供一個單獨的字符串。在您的代碼中,多個參數組合在一個字符串中。試試這個:
new?ProcessBuilder(?"sudo",?"su",?"-",?"USER66",?"-c",?"'ssh?remote.mycomp.org?<?/script_cluster.sh'");
(將 -c 標志的值視為一個參數應該是正確的。)
解釋
大多數創建新進程的本機系統方法都要求每個參數作為數組的單獨元素(例如,查看execve文檔)。
在運行時,Java 會將參數編碼為一個連續字節數組,然后將其傳遞給本機 JVM 方法,該方法將調用本機系統方法。例如"su", "-", "USER66", "-c", "'...'"
將被解碼為su-USER66-c'...'
.?各個參數由 0 字節分隔(我們在字符串中看不到)。本機 JVM 方法通過用 0 字節分隔符分割字符串來解碼連續字符串。如果我們"su - USER66"
將其作為一個參數,它將被錯誤地編碼為本機系統方法的一個參數。
當您從 shell 或 bash 調用該命令時,參數也會被拆分為一個數組,然后再傳遞給下劃線本機系統方法。
添加回答
舉報
0/150
提交
取消