【问题标题】:Problem calling java.lang.Runtime.exec(String) with parameters with spaces使用带空格的参数调用 java.lang.Runtime.exec(String) 时出现问题
【发布时间】:2019-07-12 07:19:42
【问题描述】:

我尝试从 java 进程中的特定位置调用带有文件的 vim 编辑器:

Runtime.getRuntime().exec("gvim /etc/fstab '+normal GW'");

不幸的是,这不起作用。它从 gvim 发出一条奇怪的错误消息,这无助于发现问题(“/etc/fstab”“/etc/fstab”[只读] 12L,664C)。

直接在终端输入同样的命令效果很好。

我尝试修改命令:

Runtime.getRuntime().exec("gvim /etc/fstab +normal\ GW");

直接在终端中输入时也可以使用。但这给出了完全相同的行为。

的作用是将命令及其参数拆分成一个字符串[]:

Runtime.getRuntime().exec(new String[]{"gvim", "/etc/fstab" ,"+normal GW"});

这种行为的原因是什么? 如何在 Java 中将上述命令作为单个字符串调用

【问题讨论】:

  • 使用 ProcessBuilder。 ProcessBuilder pb = new ProcessBuilder("gvim","/etc/fstab","'+normal\ GW'"); pb.start();
  • @PrasanthGanesan 也不是单个字符串。
  • 然后this 可以工作
  • @PrasanthGanesan 不,这显示了完全相同的行为。

标签: java


【解决方案1】:

exec 不是一个完整的外壳。

为方便起见,它确实允许您传递带有可执行名称和参数的单个字符串(与使用 String[] 版本相反),但它用于拆分该字符串的逻辑非常简单,它只是调用 new StringTokenizer(command),它只是被空格分割,并且不了解完整的命令 shell 会提供的特殊引用和转义行为。

所以你的单引号没有被尊重。

gvim /etc/fstab '+normal GW'   // last quoted section supposed to be a single arg

变成

String[]{ "gvim", "/etc/fstab", "'+normal", "GW'" } // four args instead of three

如何在 Java 中将上述命令作为单个字符串调用?

你真的需要这个吗?除非应用程序动态地接受来自交互式用户的命令行输入,否则在编写程序时应该可以拆分参数。这样更安全。

如果你真的需要这个,你可以将整个字符串传递给命令 shell。

试试Runtime.getRuntime().exec(new String[]{"bash", "-c", theCommand });

但有一些开销。

除此之外,您可以尝试找到一个可以“正确”拆分字符串的 Java 库。

【讨论】:

  • 请注意,与 StringTokenizer 不同,Stackoverflow 语法高亮器确实理解第一个代码块中的引号并正确地为参数着色。
  • Unless the application dynamically accepts command line input from an interactive user。不幸的是,情况就是这样。我的例子只是一个可能的例子。因为它甚至应该在 Windows 下工作,所以我不想调用特定的 shell(如 bash)。不得不考虑一下。但感谢您的解释。以如此简单的方式对字符串进行标记是实际问题。也许自己这样做可能是一个解决方案。
【解决方案2】:

根据文档exec(String command) 将整个字符串视为命令,如果我们查看文档

public Process exec(String command)
         throws IOException

在单独的进程中执行指定的字符串命令。

这是一种方便的方法。调用 exec(command) 形式的行为与调用 exec(command, null, null) 完全相同。

参数:

command - 指定的系统命令。

来到exec(String[] cmdarray),它会将 cmdarray 视为包含要调用的命令及其参数的数组。这是这两种方法之间的唯一区别,可能是问题

public Process exec(String[] cmdarray)
         throws IOException

在单独的进程中执行指定的命令和参数。

这是一种方便的方法。 exec(cmdarray) 形式的调用与调用 exec(cmdarray, null, null) 的行为方式完全相同。

参数:

cmdarray - 包含要调用的命令及其参数的数组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-10
    • 2019-10-20
    • 1970-01-01
    • 2018-10-21
    • 2014-05-17
    • 1970-01-01
    • 2019-03-22
    相关资源
    最近更新 更多