猿问

无法调试 ProcessBuilder

我需要使用 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();

  }

我在这里缺少什么?我还能做些什么来了解正在发生的事情?


慕少森
浏览 136回答 2
2回答

哈士奇WWW

好吧,我找到了一个令人惊讶的方法来解决这个问题:诀窍不是分割参数,而是使用“bash -c”重新组合它们:processBuilder&nbsp;=&nbsp;new&nbsp;ProcessBuilder("bash",&nbsp;"-c",&nbsp;"sudo&nbsp;su&nbsp;-&nbsp;USER66&nbsp;-c&nbsp;'ssh&nbsp;remote.mycomp.org&nbsp;<&nbsp;"&nbsp;+&nbsp;workingDir&nbsp;+&nbsp;"/script_cluster.sh'");请注意,这是多么不直观,因为没有人会在 shell 中这样编写它,并且使用正确的嵌套转义将其转换为 shell 命令可能会变得非常困难。另外,如果将 3 个命令用空格连接起来,也不会形成有效的命令。

慕尼黑的夜晚无繁华

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 调用该命令时,参数也会被拆分为一个数组,然后再传递给下划线本机系统方法。
随时随地看视频慕课网APP

相关分类

Java
我要回答