【问题标题】:How to start a process from Java with arguments which contain double-quotes如何使用包含双引号的参数从 Java 启动进程
【发布时间】:2013-08-08 14:24:13
【问题描述】:

我需要从我的 Java 程序启动第二个 Java 进程,并且分叉进程的参数之一需要包含文字双引号字符 (")。我如何以可移植的方式做到这一点,即它至少可以在 Linux 和 Windows 上运行?


我尝试使用带有字符串数组作为命令行的ProcessBuilder(引入它是为了克服Runtime 类的问题,对吧?),但包含引号的参数仍然存在问题:

List<String> commandLine = new ArrayList<String>();
commandLine.add(new File(System.getProperty("java.home") + "/bin/java").getAbsolutePath());
commandLine.addAll(Arrays.asList("-jar", "plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar", "-application", "org.eclipse.equinox.p2.director", "-repository", "http://download.eclipse.org/releases/juno"));
commandLine.add("-list");
commandLine.add("Q:select(x | x.id == \"org.eclipse.sdk.ide\")");

new ProcessBuilder().command(commandLine).directory(eclipseInstallationDir).start().waitFor();

上面的代码不起作用(在 Windows 上),因为 ProcessBuilder(或其他东西)占用了最后一个参数中的双引号:

进程接收到参数Q:select(x | x.id == org.eclipse.sdk.ide),而不是Q:select(x | x.id == "org.eclipse.sdk.ide"),然后失败。


我发现我可以通过在需要" 的参数中添加\" 来使其在Windows 上运行,即

commandLine.add("Q:select(x | x.id == \"org.eclipse.sdk.ide\")".replace("\"", "\\\""));

但这会破坏 Linux 上的调用(正如 morgano 所证实的那样)。所以我不得不再次检测操作系统。在 Java 中真的没有简单、可移植的方法来启动一个参数正是字符串数组的内容的进程吗?

【问题讨论】:

  • 你的代码适合我
  • 哪一个?有或没有替换的那个?在哪个操作系统上?
  • 第一个(带有"Q:select(x | x.id == \"org.eclipse.sdk.ide\")"字符串的那个)
  • 如果在 Java 中附加 .replace("\"", "\\\"") 会发生什么? Linux 中的分叉进程是否会看到带有文字反斜杠的参数?
  • 替换如你所说,Linux“看到”这个参数:Q:select(x | x.id == \"org.eclipse.sdk.ide\")

标签: java command-line process command-line-arguments


【解决方案1】:

通常,命令参数字符串在空格周围分割以形成参数数组。但是,如果您希望单个参数包含空格,则可以将参数括在引号中。稍后,每个 pair 引号将从字符串中删除。删除这些引号的不是 java,而是操作系统本身。

ProcessBuilder 将您提供的每个参数包装在引号中,这样如果任何参数包含空格,它就不会被操作系统进一步拆分为多个参数(您可以通过提供 @987654322 来破解此问题@; 这将最终成为两个参数:12345678)。然后 ProcessBuilder 将所有参数连接到一个命令中,并将其传递给操作系统。稍后,操作系统通过空格和引号(如上所述)分割命令字符串,然后在开始新进程之前从每个字符串参数中删除所有引号对。要转义引号(即,将其视为操作系统解析器不会以不同方式处理的常规字符),请在其前面使用反斜杠字符。这是 Linux 和 Windows 的命令行转义字符。这看起来像:\\\"

【讨论】:

  • 为什么会有“更远的路”?我有一个完美的论点清单,不需要任何魔法。为什么ProcessBuilder 不能简单地将这些传递到另一个进程?另外,我怀疑这一切都只发生在 Windows 上(参见this comment
  • “更进一步”是操作系统本身。 ProcessBuilder 正在创建一个新进程,就像您在命令提示符窗口中手动创建的一样。它只是将您提供给操作系统的参数传递给操作系统。
  • 您给出的答案仅适用于Windows。在Linux中,如果你传递\"的参数,传递的正是\",因为参数作为char数组列表传递给操作系统,然后作为列表传递给进程对于 char 数组,不进行任何处理。在 Windows 上情况有所不同,这是 JDK 的错误,它没有抽象出这种差异,因此在任何一种情况下行为都是相同的。
  • @JamesRoper 好的,感谢您提供的信息。最终可能不得不编写一堆样板代码来创建跨平台解决方案。
猜你喜欢
  • 2013-06-01
  • 2020-07-25
  • 2018-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多