4

I have written a small java code with getRuntime() API to copy files from One directory to another, it it failing, I am not able to understand why? When I run the command from shell it runs fine, can anyone, please let me know the mistake I am doing

    private static void copyFilesLinux(String strSource, String strDestination) {

    String s;
    Process p;
    try {
        // cp -R "/tmp/S1/"*  "/tmp/D1/"
        p = Runtime.getRuntime().exec(
                "cp -R '" + strSource + "/'* '" + strDestination + "/'");
        System.out.println("cp -R \"" + strSource + "/\"* \"" + strDestination + "/\"");
        System.out.println("cp -R '" + strSource + "/'* '" + strDestination + "/'");
        System.out.println(p.toString());
        BufferedReader br = new BufferedReader(new InputStreamReader(
                p.getInputStream()));
        while ((s = br.readLine()) != null)
            System.out.println("line: " + s);
        p.waitFor();
        System.out.println("exit: " + p.exitValue());
        p.destroy();
    }
    catch (InterruptedException iex) {
        iex.printStackTrace();
    }
    catch (IOException iox) {
        iox.printStackTrace();
    }
    catch (Exception e) {
        e.printStackTrace();
    }

}

Output:

cp -R "/tmp/S1/"* "/tmp/D1/"

cp -R '/tmp/S1/'* '/tmp/D1/'

java.lang.UNIXProcess@525483cd

exit: 1
Sandeep540
  • 897
  • 3
  • 13
  • 38
  • Shouldn't the * be inside the quotes? Like: `cp -R "/tmp/S1/*" "/tmp/D1/"` – Ash Mar 07 '13 at 07:45
  • 1
    @Ash: in this case it would make no difference - wildcards are not expanded in `Runtime.exec()`. In a shell prompt, though, placing the `*` within the quotes would prevent expansion through globbing - that is generally not what one would want... – thkala Mar 07 '13 at 07:58
  • This is the error I got cp: cannot stat `/tmp/S1/*': No such file or directory – Sandeep540 Mar 07 '13 at 07:59

4 Answers4

4

It works with the below code,

            String[] b = new String[] {"bash", "-c", "cp -R \"" + strSource + "/\"* \"" + strDestination + "/\""};  
        p = Runtime.getRuntime().exec(b);

I googled it and found the link

http://www.coderanch.com/t/423573/java/java/Passing-wilcard-Runtime-exec-command

Sandeep540
  • 897
  • 3
  • 13
  • 38
2

When you use any variation of Runtime.exec(), the binary is called directly, rather than through a shell. That means that wildcards are not supported, because there is no shell to expand them.

I would suggest using Java code to copy your files - it would be far more portable and much safer. Barring that, you can use a shell binary to execute your command via its -c option.

Community
  • 1
  • 1
thkala
  • 84,049
  • 23
  • 157
  • 201
  • Lets say I use "FileUtils" class from apache commons-io library to copy files from Folder A to B, will it transfer files at OS level (or) will it use JVM? I am asking since, I have files with size more than 1GB, and it might be an issue if JVM is involved – Sandeep540 Mar 07 '13 at 08:01
  • _thkala_ is right. Just extending his answer. Run your copy as _"bash -c cp -R dir1 dir2"_ or _"sh -c cp ..."_ – Vasyl Keretsman Mar 07 '13 at 08:10
  • Tried this - ` p = Runtime.getRuntime().exec("bash -c cp -R \"" + strSource + "/\"* \"" + strDestination + "/\"");` no luck – Sandeep540 Mar 07 '13 at 08:22
  • @Sandeep540: you need to quote the whole command when passing to `-c`. Have a look at the linked question in my answer... – thkala Mar 07 '13 at 08:24
  • got it, my mistake, let me try – Sandeep540 Mar 07 '13 at 08:27
  • Now I am getting a different error, file not found.................... `[root@vmhkgplmdev2 Desktop]# 'bash -c cp -R "/tmp/S1/"* "/tmp/D1/"' bash: bash -c cp -R "/tmp/S1/"* "/tmp/D1/": No such file or directory` – Sandeep540 Mar 07 '13 at 08:39
  • @Sandeep540: The command string should be `bash -c 'cp -r "/tmp/S1/"* "/tmp/D1"'`. I hope that by now you have realized why using `exec()` is such a bad idea... – thkala Mar 07 '13 at 09:01
  • It is pretty bad, we use kind of Java for copying files and this code is running from a server on an event, if there are files more than 1-2 GB , its taking too long time for the event to finish, I am not sure this is such a good idea, but let me finish what I started – Sandeep540 Mar 07 '13 at 09:20
  • And this keeps getting worse, I am getting exit 2, no clue what that means – Sandeep540 Mar 07 '13 at 09:23
  • @thkala : Thanks for all the help, it worked, I posted the answer below for everyone – Sandeep540 Mar 07 '13 at 09:37
1

You can do that using standard java api unless you have really a need to execute system commands.

http://docs.oracle.com/javase/tutorial/essential/io/copy.html

Vasyl Keretsman
  • 2,688
  • 2
  • 18
  • 15
  • I am using JDK 6 , cannot use JDK 7 as of now – Sandeep540 Mar 07 '13 at 08:00
  • Have a look at Apache Commons FileUtils. This can also make it easier. http://commons.apache.org/proper/commons-io///apidocs/org/apache/commons/io/FileUtils.html – Vasyl Keretsman Mar 07 '13 at 08:03
  • If I use "FileUtils" class from apache commons-io library to copy files from Folder A to B, will it transfer files at OS level (or) will it use JVM? I am asking since, I have files with size more than 1GB, and it might be an issue if JVM is involved – Sandeep540 Mar 07 '13 at 08:06
1

It worked for me with following code.

 public static void main(String []args) throws Exception{
        String s;
        Process p;
        try {
            String b[] = new String[4];
            b[0] = "cp";
            b[1] = "-R";
            b[2] = "HelloWorld.java";
            b[3] = "abc.java";

            p = Runtime.getRuntime().exec(b);
            BufferedReader br = new BufferedReader(
                new InputStreamReader(p.getInputStream()));
            while ((s = br.readLine()) != null)
                System.out.println("line: " + s);
            p.waitFor();
            System.out.println ("exit: " + p.exitValue());
            p.destroy();
        } catch (Exception e) {}        
     }
}

Create a String[] of commands and pass the commands in that.

Aimee Borda
  • 842
  • 2
  • 11
  • 22