Reputation: 11723
I need to start a second Java process from my Java program, and one of the arguments to the forked process need to contain literal double-quote characters ("
). How do I do that in a portable way, i.e. so that it at least works on Linux and Windows?
I tried to use a ProcessBuilder
(which was introduced to overcome problems of the Runtime
class, right?) with an array of strings as command line, but still there was a problem with the parameter containing the quote:
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();
The code above doesn't work (on Windows) because the ProcessBuilder
(or something else) eats up the double quotes in the last argument:
Instead of Q:select(x | x.id == "org.eclipse.sdk.ide")
, the process receives the argument Q:select(x | x.id == org.eclipse.sdk.ide)
and then fails.
I figured out that I can make it work on Windows by adding a \"
in the argument where I need a "
i.e.
commandLine.add("Q:select(x | x.id == \"org.eclipse.sdk.ide\")".replace("\"", "\\\""));
but this breaks the invocation on Linux (as morgano confirmed). So I'm forced to detect the OS again. Is there really no simple, portable way to start a process in Java where the arguments are exactly the content of a string array?
Upvotes: 3
Views: 4018
Reputation: 8617
Normally, a command argument string is split around spaces to form an array of arguments. However, if you want a single argument to contain a space, you can wrap the argument in quotes. Later, each pair of quotes will be removed from the string. It's not java that is removing these quotes--it's the operating system itself which does this.
ProcessBuilder is wrapping each of the arguments you supply in quotes so that if any of the arguments contains a space, it will not be split into multiple arguments further down the road by the operating system (you can hack this by supplying 1234\" \"5678
; this will be end up being two arguments: 1234
, and 5678
). Then ProcessBuilder concatenates all the arguments together into one command, which it passes to the operating system. Later, the operating system splits the command string by whitespace and quotes (as described above), and then removes all pairs of quotes from each string argument before it begins the new process. To escape a quote (i.e. treat it as a regular character that is not handled differently by the OS parser), use a backslash character before it. This is the command line escape character for both Linux and Windows. This will look like: \\\"
.
Upvotes: 1