PDA

View Full Version : Weird Java problem with escaped characters in system calls




mpcoder
Mar 27, 2009, 10:00 AM
I want to open applications using Runtime.getRuntime().exec() but I'm having a problem when the application's name has a space in it for example with "Quicktime Player.app" When I do this: Runtime.getRuntime().exec("open \"/Applications/Quicktime Player.app\"") it doesn't work. So to eliminate the escaping of the quotes (\") I renamed it Quicktime.app and tried Runtime.getRuntime().exec("open /Applications/Quicktime.app") and it worked fine. Then for some reason when I tried it again without the space but with the escaped quotes Runtime.getRuntime().exec("open \"/Applications/Quicktime.app\"") it doesn't work!! Even without the space!

Any ideas?



lee1210
Mar 27, 2009, 10:10 AM
i don't know if it likes the quotes. Try escaping the spaces instead, and see how that goes.

-Lee

mpcoder
Mar 27, 2009, 10:21 AM
Thanks for your reply lee.

I tried that just now and no dice. The strange thing is that when I write it myself on the command line with the escaped quotes it works just fine, the problem apparently occurs when sending it through that java method.

Guiyon
Mar 27, 2009, 10:41 AM
Try this method:


String[] cmd = new String[] { "/usr/bin/open", // The command
"--wait-apps", // Block until the app is closed, optional
"/Applications/QuickTime Player.app"
};

/* Will not return until QuickTime exists because of the
* --wait-apps argument
*/
Process qt = Runtime.getRuntime().exec( cmd );


Here's a quick test class demonstrating its use (just name it "test.java"). This isn't the cleanest code but it's a quick & simple example:
import java.io.*;

public class test {
public static void main (String [] args)
{
try {
String[] cmd = new String[] { "/usr/bin/open", // The command
"--wait-apps", // Block until the app is closed
"/Applications/QuickTime Player.app"
};

Process qt = Runtime.getRuntime().exec( cmd );

if( qt == null ) {
System.out.println( "Error while exec'ing command." );
} else {
int result = -1;
char[] buf = new char[256];
StringBuffer sb = new StringBuffer();
Reader isr = new InputStreamReader( qt.getErrorStream() );

while( (result = isr.read(buf, 0, buf.length)) != -1 ) {
sb.append( buf, 0, result );
}

if( sb.length() > 0 ) {
System.out.println( "STDERR said:\n"+sb.toString() );
System.out.println( "*********" );
}


/* Finished up with the STDERR output, now print the
* STDOUT
*/
sb = new StringBuffer();
isr = new InputStreamReader( qt.getInputStream() );
while( (result = isr.read(buf, 0, buf.length)) != -1 ) {
sb.append( buf, 0, result );
}

if( sb.length() > 0 ) {
System.out.println( "STDOUT said:\n"+sb.toString() );
System.out.println( "*********" );
}
}
} catch( IOException ioe ) {
System.out.println( "Exception: "+ioe );
}
}
}

macsmurf
Mar 27, 2009, 11:40 AM
The quotes is for the benefit of your terminal shell in order for it to interpret your command properly. You're not going through bash (or similar) in java, so the quotes will be interpreted as a part of the filename.

In addition, you're using a convenience method in Runtime that does not work well with spaces because, according to the documentation and the source-code, exec uses a standard StringTokenizer to convert the command from a String to a String Array. Here is the problem:


public Process exec(String command, String[] envp, File dir)
throws IOException {
if (command.length() == 0)
throw new IllegalArgumentException("Empty command");

StringTokenizer st = new StringTokenizer(command);
String[] cmdarray = new String[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++)
cmdarray[i] = st.nextToken();
return exec(cmdarray, envp, dir);
}


So, in order for you to ensure that the command is interpreted properly, you need to construct the String array yourself. In other words, do what Guiyon suggested :)

mpcoder
Mar 27, 2009, 11:55 AM
Wow that was it! I built the array myself and it worked.

Thank you all for your quick responses!