9

How can I make the following run?

public class ExecTest {
  public static void main(String[] args) {
    try {
      //Notice the multiple spaces in the argument
      String[] cmd = {"explorer.exe", "/select,\"C:\\New      Folder\\file.txt\""};

      //btw this works
      //String cmd = "explorer.exe /select,\"C:\\New Folder\\file.txt\"";

      //and surprisingly this doesn't work
      //String[] cmd = {"explorer.exe", "/select,\"C:\\New Folder\\file.txt\""};

      //Update: and (as crazy as it seems) the following also worked
      //String[] cmd = {"explorer.exe", "/select,\"C:\\New", "Folder\\file.txt\""};

      Runtime.getRuntime().exec(cmd);
    } catch (Exception e) {
        e.printStackTrace();
    }
  }
}

Using Java 6. Tested under Vista x64. By the way, taking the string that gets executed (you'll have to use the String version of exec to get it) and using it in the Search field of Vista's start menu will run as expected.

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Minos
  • 151
  • 1
  • 1
  • 7
  • Is there a typo in the first case? I suspect that in second "btw" case, the /select is being treated oddly, because it's part of arg[0]. Providing a dir as an arg will open that folder. Given that they're all named the same, you could easily miss that it was one lower than you expected. I'd rename them to be different. – Ed Staub Jul 13 '11 at 23:03
  • Well the first and second btw cases are the same commands. Here I 'm just demonstrating that the array version of exec **fails** in this case, while the string version **worked**. The path is there, and it's irrelevant i m afraid, i could have used anything.. thnx for answering – Minos Jul 13 '11 at 23:10

9 Answers9

6

A miracle, it works!

Don't ask me why, but when i, after quite a while of nerve-wrecking research in the internets, was close to give up and use a temporary batch file as a workaround, i forgot to add the /select, parameter to the command, and, who would have thought, the following works on my Win 7 32Bit System.

String param = "\"C:\\Users\\ME\\AppData\\Local\\Microsoft\\Windows\\Temporary Internet Files\\\"";
try {
    String[]commands = new String[]{"explorer.exe", param};
    Process child = Runtime.getRuntime().exec(commands);
} catch (IOException e1) {
    System.out.println("...");
}

General Solution:

The solution of the bug-database mentioned by prunge in his post (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6511002) worked fine for me.

Reason:

Apparently the problem lies with the commenting of some characters done by java which it does before actually executing the command string. You have to do the commenting yourself by tokenizing your command string, to prevent the faulty java one to spring into action and mess everything up.

How to fix:

So, in my case i had to do the following (tokenizing my command string, so that no spaces are left inside the string):

String param[] = {
    "explorer.exe",
    "/select,C:\\Users\\ME\\AppData\\Local\\Microsoft\\Windows\\Temporary",
    "Internet",
    "Files\\"};

try {
    Process child = Runtime.getRuntime().exec(param);
} catch (IOException e1) {
    System.out.println("...");
}

As you can see i basically started a new String wherever a space occured, so "Temporary Internet Files" became "Temporary","Internet","Files".

Larzan
  • 9,389
  • 3
  • 42
  • 41
6

Ok, this is not simply an update but also an answer so I'm filing it as one. According to all information I could find, the following should theoretically do it:

String[] cmd = {"explorer.exe", "/select,\"C:\New", "", "", "", "", "", "", "Folder\file.txt\""};

The multiple spaces have been broken into empty strings and the array version of exec is used. Using the above array, I debugged the loop in lines 50-75 of java.lang.ProcessImpl where a string is finally constructed. The resulting string was:

explorer.exe /select,"C:\New       Folder\file.txt"

This is what is passed as the 1st argument to ProcessImpl's native create method (line 118 same class), which as it seems fails to run properly this command.

So I guess it all ends here... sadly.

Thnx prunge for pointing out the java bug. Thnx everyone for their time and interest!

Minos
  • 151
  • 1
  • 1
  • 7
  • And now I'm looking for alternative ways to do this. Using jni is an option but leads to different versions of your app for 32 or 64 bit systems. Currently I'm looking into an insane solution, which in short is opening a bat file, writing the cmd in and executing the bat. Average total time is 45ms. That's excellent, the explorer.exe process takes about 500ms so this goes unnoticeable. Also this way you can exec literally everything. wdyt? – Minos Jul 17 '11 at 10:59
5

Always use Runtime.exec(String[]), not Runtime.exec(String) unless the command line is extremely simple.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I will have to disagree based on my case, since using the array version fails while the string version works. You can uncomment my code and see for yourself. I know all about the tokenizer and the problem it creates, but it doesn't help in this case. And it really is a simple command right? So my opinion would be... with Runtime.exec, use whatever you manage to get it working!! – Minos Jul 14 '11 at 17:09
  • Minos that's because you have already compensated for the parsing in the single-arg version by quoting etc. If you use the other you only have to pass the actual values, no quotes, no second-guessing required. – user207421 Jul 15 '11 at 00:00
  • Don't really get it. How can this be written without escaping quotes? `String[] cmd = {"explorer.exe", "/select,\"C:\\New Folder\\file.txt\""};`. If you don't quote the path, and let exec do it for you then you 'll get the `/select,` part of the argument also quoted. Explorer will definitely not like this. Even if this is the only command with this awkwardness (not the case) this still seems buggy..when the string version works exactly as someone would expect – Minos Jul 16 '11 at 02:27
  • @Minos `{"explorer.exe", "/select", "C:\\New Folder\\file.txt"}`. – user207421 Jul 16 '11 at 02:32
  • This will end up in the following command: `explorer.exe /select "C\New Folder\file.txt"`. This, simply put is **wrong**. It is not the command I'm after. There is a space between /select and the path. Also in your example you've missed the comma after /select, but anyway the main problem is the space you introduced. Checking if explorer can handle the extra space, I see that it does, so I'll give a plus for your answer. But in general, I find it annoying that I cannot exec exactly the command I want. Why can't my string be left as is.. – Minos Jul 16 '11 at 12:00
  • @Minos The spaces in that line are between array elements, not inside them: they are ignored by the compiler, so they are not present at runtime to be passed to exec(). So i introduced no space. The *entire purpose* of this overload is to leave your arguments alone. If there is a comma missing, put it back. If it works what exactly are you annoyed about now? – user207421 Jul 16 '11 at 12:55
  • But my argument is only one:`/select,"path"` I quote the path cause this is what explorer.exe expects. This 1 argument does not have spaces anywhere but inside the path. So I don't get why you've separated `/select,` as a different array element. Why do you break the argument after select? The array version adds a space for each element of the cmdarray you give it. And that's what I see in java.lang.ProcessImpl. So you must be getting a space between `/select,` and the quoted path. Luckily explorer likes it. Btw, you realize we are not discussing an answer to the multiple spaces problem... – Minos Jul 16 '11 at 16:37
  • @Minos No. the array version doesn't add any spaces. The cmd[] array becomes the argv[] of target take directly, no parsing, no spaces added, nothing. If that's all one argument, try {"explorer.exe", "/select,C:\\New Folder\\file.txt"}. – user207421 Jul 16 '11 at 23:03
  • EJP, please take a look at lines 50-75 in java.lang.ProcessImpl. In the first statement of the for loop, a single space is inserted for every element in cmdarray. I'm on Java 6 btw – Minos Jul 17 '11 at 00:37
  • @Minos faIr enough, I am crazy again. Did the variant I just posted work? – user207421 Jul 17 '11 at 02:06
  • Well the variant will work unless the `/select,` gets quotes. To prevent that I had to put it together with the path as 1 argument. Then, explorer.exe requires a quoted path. So I have to escape only the path part of this 1 arg! Also I need to account for the bug pointed out by prunge, since my path has spaces! So, your variant works if written like this (finally!): `String[] cmd = {"explorer.exe", "/select,\"C:\\New", "Folder\\file.txt"};`. Crazy enough but works! – Minos Jul 17 '11 at 10:48
  • @Minos {"explorer.exe", "/select,\"C:\\New Folder\\file.txt\""}? NB the 'bug' is still only a documentation RFE. – user207421 Jul 17 '11 at 12:50
  • I expected that to work initially but it didn't. And it's the rfe that causes the problem. Looking again into ProcessImpl, this is what you get: `explorer.exe \"/select,\"C:\\New Folder\\file.txt\"\""` The arg has spaces, so it got quoted. No check was done to see if arg contains quotes.. only the first character is checked. So `/select,` is inside quotes now, and explorer.exe doesn't like this – Minos Jul 17 '11 at 13:08
  • In my humble opinion EJP is correct in almost all cases. i had a similar problem where the space character was at different interval not all of them at the same time. Minos's method did not work for me at all. In my case the String Array method worked. Process Builder method works better when more control is needed and this problem is solved easily in that class. Although my comment does not answer the question but posting it for clarification as i found my problem's solution from EJP's suggestion. – Yeasin Ar Rahman Mar 19 '17 at 18:19
2

The characters ,-& and double spaces, all combined are a nightmare!

All the answers exposed here failed for "\\NAS\media\Music\Artistes\E\Earth, Wind & Fire\1992 - The eternal dance - Vol. 1 (1971-1975) (double space between 'Vol. 1' and '(1971').

I have no other choice than writing a temporary batch file:

   void openFolderOf( Album album ) {
      try {
         final String path = album._playList.getParent();
         final File batch = File.createTempFile( getClass().getSimpleName(), ".bat" );
         try( PrintStream ps = new PrintStream( batch )) {
            ps.println( "explorer.exe \"" + path + '"' );
         }
         Runtime.getRuntime().exec( batch.getAbsolutePath());
      }
      catch( final Throwable t ) {
         t.printStackTrace();
      }
   }

Note: on cmd.exe, the line explorer "\\NAS..." works well but not with Runtime.exec() nor ProcessBuilder.

Aubin
  • 14,617
  • 9
  • 61
  • 84
  • This also was the only way that worked for me, thanks but I used buffer writer instead: File batch = File.createTempFile( "bat" + cuid, ".bat" ); BufferedWriter txt = new BufferedWriter(new FileWriter(batch.getAbsolutePath())); txt.write(winrarcmd); txt.close(); – azerafati Apr 01 '14 at 07:01
2

Use new File(pathName).canExecute() first to check whether it's executable or not

EDIT:

public static void runAll(String... cmd)
{
    for(String s : cmd)
    {
        try
        {
            Runtime.getRuntime().exec(cmd);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}

and then you can use it like: runAll("explorer.exe", "taskmgr.exe");

Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
  • yes explorer is an executable in vista. Are you not talking about explorer? Also, please see my comments. How come the other commands work? – Minos Jul 13 '11 at 22:59
  • @Minos I don't understand your question well but see the update, is this what you're looking for? – Eng.Fouad Jul 13 '11 at 23:10
  • Sorry to ask, but did you try to run my main? My question is not on how to architect this, but why that completely simple code block I posted does not run as expected. Thnx.. – Minos Jul 13 '11 at 23:14
  • @Minos OK. well, maybe you have to run the program as administrator – Eng.Fouad Jul 13 '11 at 23:19
  • Sure, but then why don't i need to be admin also in the non multiple spaces case? How come when there are only single spaces it works? I tried it anyway.. – Minos Jul 13 '11 at 23:27
1

Could be a Java bug. See: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6511002

Did a bit of debugging out of curiosity, I think things are becoming unstuck in java.lang.ProcessImpl (see the constructor). Noticed that when it got to actually calling the underlying Windows API the string had turned into

explorer.exe "/select,"c:\New Folder\test.txt""

So that might explain why, as for workarounds see the bug database link.

prunge
  • 22,460
  • 3
  • 73
  • 80
  • That's not a bug: it is an RFE (Request for Enhancement). Specifically it is a request to document the *existing* behaviour. – user207421 Jul 14 '11 at 04:25
  • Thank you prunge! i did some debugging as well and reached the exact same conclusion with you, the multiple spaces get trimmed (by the tokenizer on ' ' i guess) and you end up with a single space instead. No matter if you use the string or the array version of exec. A breakpoint at line 452 of the java.lang.ProcessBuilder reveals that. I will take a look at the bug you mentioned and post any findings. Thnx very very very much – Minos Jul 14 '11 at 17:14
0

For your specific case of needing the reveal/select command, I get around the windows quote nightmare by using cmd /c start:

String[] cmd = {"cmd", "/c", "start explorer.exe /select," + path};

Where path is the absolute path from a File object.

Kelly
  • 1,096
  • 12
  • 22
0

A better way to do it would be using ProcessBuilder object:

 Process p;
 p = new ProcessBuilder("/Applications/Sublime Text.app/Contents/MacOS/sublime_text", homeDir + _CURL_POST_PUT_CMDS).start();
 int exitValue = p.waitFor();
 if (exitValue != 0){
    System.out.println("Error to open " + homeDir + _CURL_POST_PUT_CMDS);
 }
Andie
  • 23
  • 8
-1

Simple way to resolve this problem for files is java.awt.Desktop Since 1.6 Example:

   Desktop.getDesktop().open(new File(fullFileName));
Mumish
  • 1
  • 1