3 Replies Latest reply: Jul 19, 2011 5:21 PM by 796440 RSS

    How to execute unix commands through Windows/cygwin using Java

    864501
      I am trying to accomplish two things:

      1. I am running cygwin on Windows7 to execute my unix shell commands and I need to automate the process by writing a Java app. I already know how to use the windows shell through Java using the 'Process class' and 'Runtime.getRuntime().exec(cmd /c dir)'. I need to be able to do the same with unix commands: i.e.: 'ls -la' and so forth. What should I look into ?
      I have tried running 'Runtime.getRuntime().exec("C:\\cygwin\\bin\\mintty.exe -e ls -la")' or 'Runtime.getRuntime().exec("C:\\cygwin\\bin\\bash.exe -c ls -la");', but for some reason, both mintty and bash end up not recognizing basic commands like the 'ls' when they are called this way !?

      2. Is there a way to remember a shell's state? explanation: when I use: 'Runtime.getRuntime().exec(cmd /c dir)' I always get a listing of my home directory. if I do 'Runtime.getRuntime().exec(cmd /c cd )' and then do 'Runtime.getRuntime().exec(cmd /c dir)' again, I will still get the listing of my home folder. Is there a way to tell the process to remember its state, like a regular shell would?
        • 1. Re: How to execute unix commands through Windows/cygwin using Java
          796440
          861498 wrote:
          I am trying to accomplish two things:

          1. I am running cygwin on Windows7 to execute my unix shell commands and I need to automate the process by writing a Java app. I already know how to use the windows shell through Java using the 'Process class' and 'Runtime.getRuntime().exec(cmd /c dir)'. I need to be able to do the same with unix commands: i.e.: 'ls -la' and so forth. What should I look into ?
          I have tried running 'Runtime.getRuntime().exec("C:\\cygwin\\bin\\mintty.exe -e ls -la")' or 'Runtime.getRuntime().exec("C:\\cygwin\\bin\\bash.exe -c ls -la");', but for some reason, both mintty and bash end up not recognizing basic commands like the 'ls' when they are called this way !?
          I believe to do it that way it would be
          exec("C:\\cygwin\\bin\\bash.exe -c 'ls -la'");
          Note also that
          exec("C:/cygwin/bin/bash.exe -c 'ls -la'");
          will work, and is less ugly, and easier to type.

          Note the single quotes around 'ls -la', which I believe get stripped off, so that the command that bash sees is "ls" with the arg "-la".

          I think something like this worked for me:
          C:/cygwin/bin/rxvt.exe -geometry 130x16 -e /bin/zsh -l -c 'ssh -X jeff@lin2'
          which adds the extra layer of the terminal that then invokes a shell, but if you strip that off and start with the /bin/zsh, it looks like my modification to your original attempt.

          You may want to use the exec signature that takes an array, where the first element is the command and the remaining elements are its args, or use ProcessBuilder, which I think only works that way. If you do, it would be:
          [0] C:/cygwin/bin/rxvt.exe
          [1] -geometry
          [2] 130x16 
          [3] -e 
          [4] /bin/zsh 
          [5] -l
          [6] -c
          [7] 'ssh -X jeff@lin2' // yes, the single quotes need to be part of args[7]
          2. Is there a way to remember a shell's state? explanation: when I use: 'Runtime.getRuntime().exec(cmd /c dir)' I always get a listing of my home directory. if I do 'Runtime.getRuntime().exec(cmd /c cd )' and then do 'Runtime.getRuntime().exec(cmd /c dir)' again, I will still get the listing of my home folder. Is there a way to tell the process to remember its state, like a regular shell would?
          This is not a Java question.

          I think it's rather odd that your definition of a "regular" shell is based on what you observed with a Windows command prompt. Linux shells don't work that way. As documented in the man pages, when a shell starts up, it reads its config from the command line, the appropriate common files in /etc, (e.g. /etc/profile) and the user's files (e.g. ~/.bash_profile and ~/.bashrc). If you look at the man pages for bash or zsh, you might find some option that tells it to write out its state on exit, and another to read that state on startup. I've never seen one, but that doesn't mean it's not there. Again, though, this has nothing to do with Java.

          Edited by: jverd on Jul 19, 2011 1:18 PM

          Edited by: jverd on Jul 19, 2011 1:26 PM
          • 2. Re: How to execute unix commands through Windows/cygwin using Java
            864501
            it appears then only the following works:

            p = Runtime.getRuntime().exec("c:\\cygwin\\bin\\ls -la ~/\"Eclipse_Workspace/RenameScript/files copy\"");

            everything else, including calling 'bash.exe' with the '-c' gives me: "Unknown command"

            i.e.: p = Runtime.getRuntime().exec("bash -c ls -la ~/\"Eclipse_Workspace/RenameScript/files copy\"");

            the same if i use an array of srings for arguments, rather then one big string.

            Edited by: 861498 on Jul 19, 2011 2:34 PM

            Edited by: 861498 on Jul 19, 2011 2:36 PM
            • 3. Re: How to execute unix commands through Windows/cygwin using Java
              796440
              The following works for me. Of special note:

              1) When using the single string version, the single quotes are required around '/bin/ls -la', so that it can be treated as the single param to the -c option. However, they are not needed in the array form, because being an single element of the array already handles that.

              2) I had to explicitly do */bin/ls*, not just ls, since the -c option skips some or all of the files that set up your environment. Using -l or --login might fix that. I don't know. This is a bash issue, not a Java issue.

              3) Make sure you read this, for proper handling of in, out, and err streams: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html. I shortcutted it, to simplify the demo.
              import java.io.BufferedReader;
              import java.io.InputStream;
              import java.io.InputStreamReader;
              import java.util.Arrays;
              
              public class CygwinExec {
                  public static void main(String[] args) throws Exception {
                      Process p;
                      InputStream in;
                      BufferedReader br;
                      String line;
              
                      // using single command String
                      {
                          String cmd;
                          cmd = "C:/cygwin/bin/bash -c '/bin/ls -la'";
                          System.out.println("EXECING: " + cmd);
                          p = Runtime.getRuntime().exec(cmd);
              
                          in = p.getInputStream();
                          br = new BufferedReader(new InputStreamReader(in));
                          System.out.println("OUT:");
                          while ((line = br.readLine()) != null) {
                              System.out.println(line);
                          }
              
                          in = p.getErrorStream();
                          br = new BufferedReader(new InputStreamReader(in));
                          System.out.println("ERR:");
                          while ((line = br.readLine()) != null) {
                              System.out.println(line);
                          }
              
                          System.out.println();
                      }
              
                      // using command array
                      {
                          String[] cmdArray;
                          cmdArray = new String[] {"C:/cygwin/bin/bash", "-c", "/bin/ls -la"};
                          System.out.println("EXECING: " + Arrays.toString(cmdArray));
                          p = Runtime.getRuntime().exec(cmdArray);
              
                          in = p.getInputStream();
                          br = new BufferedReader(new InputStreamReader(in));
                          System.out.println("OUT:");
                          while ((line = br.readLine()) != null) {
                              System.out.println(line);
                          }
              
                          in = p.getErrorStream();
                          br = new BufferedReader(new InputStreamReader(in));
                          System.out.println("ERR:");
                          while ((line = br.readLine()) != null) {
                              System.out.println(line);
                          }
              
                          System.out.println();
                      }
                  }
              }