我需要使用java.lang.ProcessBuilder将使用“ sudo”和“ su”的不同sh命令从我的Java应用程序传递到linux。
这些命令非常相似,但是有些工作可行,有些却没有。当我从日志中粘贴命令时, ALL 命令起作用。
在此之后:
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();
}
我在这里想念什么?我还能做些什么才能了解发生了什么事?
答案 0 :(得分:0)
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调用命令时,参数也将拆分为数组,然后传递给下划线本机系统方法。
答案 1 :(得分:0)
好吧,我找到了解决这个问题的令人惊讶的方法:
诀窍不是拆分参数,而是使用“ bash -c”重新组合参数:
processBuilder = new ProcessBuilder("bash", "-c", "sudo su - USER66 -c 'ssh remote.mycomp.org < " + workingDir + "/script_cluster.sh'");
注意这是多么不直观,因为没有人会在shell中这样写它,而在具有适当的嵌套转义的shell命令中转换它可能会变得非常困难。另外,如果将3条命令与空格连接在一起,则它不会形成有效的命令。