使用带空格的参数调用java.lang.Runtime.exec(String)时出现问题

时间:2019-07-12 07:19:42

标签: java

我尝试用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");

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

做什么的工作原理是将命令及其参数拆分为String []:

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

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

2 个答案:

答案 0 :(得分:1)

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

public Process exec(String command)
         throws IOException
  

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

     

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

参数:

命令-指定的系统命令。

进入exec(String[] cmdarray)时,它将cmdarray视为包含调用命令及其参数的数组。这是这两个方法之间唯一的差异

public Process exec(String[] cmdarray)
         throws IOException
  

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

     

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

参数:

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

答案 1 :(得分:1)

exec不是完整的shell。

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

因此您的单引号不受尊重。

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中以单个字符串的形式调用上述命令?

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

如果您确实需要这样做,可以将整个字符串传递给命令外壳。

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

但是涉及一些开销。

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