Java 运行时 exec() 无法正确转义字符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5969724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 13:44:55  来源:igfitidea点击:

Java Runtime exec() fails to escape characters properly

javacharacter-encodingescapingexecruntime.exec

提问by Tim Strijdhorst

This might already been answered before but that was regarding unicode and I don't think this is unicode (it's in ASCII so...).

这可能之前已经回答过,但那是关于 unicode 的,我认为这不是 unicode(它是 ASCII 所以......)。

When I execute this in my terminal there is no problem what so ever

当我在终端中执行此操作时,没有任何问题

vboxmanage setextradata "Test Machine" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/HostPort" 2222

However when I use the following in Java

但是,当我在 Java 中使用以下内容时

Runtime.getRuntime().exec("vboxmanage setextradata \"Test Machine\" \"VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/HostPort\" 2222");

It returns an error: unregistered vm '"TestMachine"'

它返回一个错误:未注册的 vm '"TestMachine"'

The same goes for parameters with spaces in them like Test\ Machine, then it doesn't escape the space.

对于其中包含空格的参数(如 Test\ Machine)也是如此,那么它就不会转义空格。

Now I think this has something to do with the character encoding, but I don't see any option to set that o_O

现在我认为这与字符编码有关,但我没有看到任何设置 o_O 的选项

回答by Edwin Buck

You are calling the program and its arguments in one pass, which effectively shoves the entire string into the processing environment (hoping for the best).

您在一次传递中调用程序及其参数,这有效地将整个字符串推入处理环境(希望最好)。

In Windows systems, the operating system makes a point of handling the executable and arguments differently, and putting them all in the same string just requires you to pick the perfect string which the environment (of which there are two that i know about) can re-parse into an argument list. The better solution is to use

在 Windows 系统中,操作系统强调以不同方式处理可执行文件和参数,将它们全部放在同一个字符串中只需要您选择环境(我知道其中有两个)可以重新生成的完美字符串-解析为参数列表。更好的解决方案是使用

Runtime.exec(new String[] {"vboxmanage", "setextradata", "Test Machine", "VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/HostPort", "2222"});

which corresponds to Runtime's

对应于 Runtime's

public Process exec(String[] cmdarray)
         throws IOException

At best, with the one string method you'll eventually find out how to hint and escape out the arguments so they don't get treated as part of the executable name, but then you'll encounter a new issue, that they get passed all as one parameter to the executable. Once you fix that depending on the environment, you'll either find that your quotes aren't getting stripped from the parameters (leading to parameters like "2222") or that Window's semi-broken argument parsing is going to parse on whitespace first (leading to parameters like ("Test). It doesn't make sense, that's why there are more than one execmethods available.

充其量,使用 one string 方法,您最终会找到如何提示和转义参数,以便它们不会被视为可执行文件名称的一部分,但随后您会遇到一个新问题,即它们被传递全部作为可执行文件的一个参数。一旦你根据环境解决了这个问题,你会发现你的引号没有从参数中剥离(导致像“2222”这样的参数)或者 Window 的半损坏参数解析将首先解析空格(导致像 ("Test) 这样的参数。这是没有意义的,这就是为什么有不止一种exec方法可用。

回答by Tim Strijdhorst

Using Runtime.exec(String)is the wrong method for this case (and generally the wrong method for passing arguments to the new process).

Runtime.exec(String)在这种情况下使用是错误的方法(通常是将参数传递给新进程的错误方法)。

Use one of the exec overloadsthat takes an array of argumentsto pass to the new process. (Or, see Paul's answer with ProcessBuilder -- neither of these approaches suffer from escaping issues).

使用一个 exec 重载,它接受一组参数传递给新进程。(或者,请参阅 Paul 对 ProcessBuilder 的回答——这些方法都没有逃避问题)。

Example:

例子:

exec(new String[] { "vbomanager",
  "setextradata", "Test Machine",
  "VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/HostPort", "2222"});

Happy coding.

快乐编码。

回答by Paul Cager

Rather than trying to quote the command line you might be better off using ProcessBuilder.command(arg0, arg1, ...)

与其尝试引用命令行,不如使用 ProcessBuilder.command(arg0, arg1, ...)

See ProcessBuilderfor details.

有关详细信息,请参阅ProcessBuilder

回答by Sven

On Windows, Runtime.exec(String[]) is unsafe as well. If the argument array contains the empty string, the empty argument is basically omitted which may lead to an invalid command line. Also, quotes within any of the arguments are not prefixed with backslashes. Also, the ProcessBuilder may add quotes to arguments without doubling the number of preceding backslashes which gives funny results if one passes a path to a folder like c:\program files\ including the trailing backslash.

在 Windows 上, Runtime.exec(String[]) 也是不安全的。如果参数数组包含空字符串,则空参数基本上被省略,这可能会导致命令行无效。此外,任何参数中的引号都不以反斜杠为前缀。此外,ProcessBuilder 可能会在参数中添加引号,而不会将前面的反斜杠数量加倍,如果将路径传递到 c:\program files\ 等文件夹,包括尾随反斜杠,则会产生有趣的结果。

Microsoft's documentation of their command line tokenizer is available here: http://msdn.microsoft.com/en-us/library/a1y7w461.aspx

Microsoft 的命令行标记器文档可在此处获得:http: //msdn.microsoft.com/en-us/library/a1y7w461.aspx

The issues I described are documented here: http://bugs.sun.com/view_bug.do?bug_id=6468220and http://bugs.sun.com/view_bug.do?bug_id=6518827

我描述的问题记录在这里:http: //bugs.sun.com/view_bug.do? bug_id= 6468220http://bugs.sun.com/view_bug.do?bug_id=6518827