radlan
radlan

Reputation: 2563

Problem calling java.lang.Runtime.exec(String) with parameters with spaces

I try to call a vim editor with a file on a specific position from within a java process:

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

Unfortunately that doesn't work. It gives a strange error message from gvim which doesn't help finding the problem ("/etc/fstab" "/etc/fstab" [readonly] 12L, 664C).

The same command directly entered into a terminal works well.

I tried to modify the command:

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

which also works when entered directly in a terminal. But this gives the exact same behaviour.

What does work ist splitting the command and its parameters into a String[]:

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

What is the reason for this behaviour? How can I call the above mentioned command as a single string from within Java?

Upvotes: 0

Views: 393

Answers (2)

Thilo
Thilo

Reputation: 262824

exec is not a complete shell.

As a convenience, it does allow you to pass a single String with both executable name and parameters (as opposed to using the String[] version), but the logic that it uses to split that String is very simple, it just calls new StringTokenizer(command), which just splits by whitespace and has no understanding of special quoting and escaping behaviour a full command shell would offer.

So your single quotes are not being respected.

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

becomes

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

How can I call the above mentioned command as a single string from within Java?

Do you really need this? Unless the application dynamically accepts command line input from an interactive user, it should be possible to split the arguments when you write the program. Much safer that way.

If you really need this, you could pass your whole string to a command shell.

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

But there is some overhead involved.

Other than that, you could try to find a Java library that can split the string "properly".

Upvotes: 2

Ryuzaki L
Ryuzaki L

Reputation: 40078

According to documentation exec(String command) is treating whole string as a command, if we look at the documentation

public Process exec(String command)
         throws IOException

Executes the specified string command in a separate process.

This is a convenience method. An invocation of the form exec(command) behaves in exactly the same way as the invocation exec(command, null, null).

Parameters:

command - a specified system command.

And coming to exec(String[] cmdarray) it will treat cmdarray as array containing the command to call and its arguments.This is the only difference between these two methods which might be the issue

public Process exec(String[] cmdarray)
         throws IOException

Executes the specified command and arguments in a separate process.

This is a convenience method. An invocation of the form exec(cmdarray) behaves in exactly the same way as the invocation exec(cmdarray, null, null).

Parameters:

cmdarray - array containing the command to call and its arguments.

Upvotes: 1

Related Questions