Weird Java problem with escaped characters in system calls

Discussion in 'Mac Programming' started by mpcoder, Mar 27, 2009.

  1. macrumors newbie

    Joined:
    Mar 21, 2009
    #1
    I want to open applications using
    Code:
    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:
    Code:
    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
    Code:
    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
    Code:
    Runtime.getRuntime().exec("open \"/Applications/Quicktime.app\"")
    it doesn't work!! Even without the space!

    Any ideas?
     
  2. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    i don't know if it likes the quotes. Try escaping the spaces instead, and see how that goes.

    -Lee
     
  3. thread starter macrumors newbie

    Joined:
    Mar 21, 2009
    #3
    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.
     
  4. macrumors 6502a

    Joined:
    Mar 19, 2008
    Location:
    North Shore, MA
    #4
    Try this method:

    Code:
    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:
    Code:
    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 );
        }
      }
    }
     
  5. macrumors 65816

    macsmurf

    Joined:
    Aug 3, 2007
    #5
    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:

    Code:
    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 :)
     
  6. thread starter macrumors newbie

    Joined:
    Mar 21, 2009
    #6
    Wow that was it! I built the array myself and it worked.

    Thank you all for your quick responses!
     

Share This Page