【问题标题】:Generate linux command with arguments in Java [closed]在Java中生成带有参数的linux命令[关闭]
【发布时间】:2024-05-04 22:00:03
【问题描述】:

我正在寻找一个库(Java/Scala),它给出一个命令和一个参数列表会生成一个String,如果将其粘贴到 bash 终端中,它将执行给定命令及其所有参数(正确转义)。

我知道java.lang.ProcessBuilder 类。如果我想将命令作为子进程执行,它会很好地工作。我正在寻找的是一个可以生成命令的字符串表示形式的库。

【问题讨论】:

    标签: java linux bash scala process


    【解决方案1】:

    我通常不会建议人们尝试编写自己的转义符,但在这种情况下这并不可怕,因为 bash 单引号字符串会正确地包含除 NUL 字节和嵌套单引号之外的每个字符:

      public static String bashEscape(String[] arguments) {
        StringBuilder sb = new StringBuilder();
        for(String arg : arguments) {
          if (arg.indexOf(0) != -1) {
            throw new IllegalArgumentException("Shell arguments can't represent NUL bytes");
          }
          sb.append("'").append(arg.replaceAll("'", "'\\\\''")).append("' ");
        }
        return sb.toString();
      }
    

    这正确转义:

    • 所有类型的引号,包括单引号、双引号、反引号和反斜杠
    • 所有形式的 shell 元字符,例如 *?![]()|<>&;$ 和空格
    • 显然是所有常规字母数字字符
    • 换行、退格和其他控制字符

    唯一需要注意的是,当您将字符串交给它时,您和您的 shell 需要就字符编码达成一致。

    【讨论】:

    • 一个小的改进是使用String#replace而不是String#replaceAll,因为在这种情况下我们不需要正则表达式匹配。
    【解决方案2】:

    您可以打印出 ProcessBuilder 将要运行的命令,然后不运行它。 “cmd”将是您的应用根据参数生成的任何命令。

    ProcessBuilder processBuilder = new ProcessBuilder(cmd);
    String command = processBuilder.command().toString();
    

    【讨论】:

    • 我用cmd="ls" 尝试了这个,这使得command 包含[ls]。当我将它复制粘贴到我的外壳中时,我得到bash: [ls]: command not found。如果我直接输入ls,它会正常列出文件。你得到不同的结果吗?
    • 哦,对了, processBuilder.command() 返回一个 List 所以你需要 String.join("", processBuilder.command()) 给你命令,或者迭代通过列表,同时将每个元素添加到字符串中,它会起作用。我假设您实际上只会在列表中拥有一个元素,因此 String.join("", processBuilder.command()) 会很简单。
    • 你通常有多个元素,例如new ProcessBuilder("ls", "-l", "My File.txt"); 如果您加入"",您将获得ls-lMy File.txt,从而产生ls-lMy: command not found。如果你加入空间,你会得到ls -l My File.txt,从而得到ls: cannot access 'My': No such file or directory。在这种情况下,等效的 bash 命令应该是例如ls -l "My File.txt" 保留最后一个参数中的空格
    • 也许发布代码对您更有利,这样我就可以用适合您需求的示例准确回答。我了解 processbuilder 需要多个参数。你确实用多个参数填充它吗?你有一个例子说明你是如何做到的吗?如果可以将它们与空格连接起来,那么这不能解决问题吗?如果您使用空格加入,您的命令将成功运行,并且您上面的 ProcessBuilder 示例确实是您在代码中使用的。
    • 我不是 OP,但不,在我的示例中加入空格不起作用,因为这无法考虑单个参数中的空格。您可以确定 OP 将使用多个参数,因为它们询问“命令和参数列表”并且 ProcessBuilder 不支持没有多个参数的参数(例如,您不能使用 new ProcessBuilder("ls -l 'My File.txt'") 因为 ProcessBuilder 不调用 shell )。