ProcessBuilder and quotes

Recently, I have spent few happy hours chasing a bug in my code. It was connected to the ProcessBuilder class. This class was introduced to Java 5 in order to simplify calling of external processes.

I needed to run following rsync command, to synchronize some files from the server. It simply takes all *.txt files from all directories and ignores all other files.


rsync -vtlr --include="*.txt" --include="**/" --exclude="*" rsync.example.org::module ./mirror

With ProcessBuilder it is easy, you just have to write the following code.



    ProcessBuilder pb = new ProcessBuilder("rsync","-vtlr""–include=\"*.txt\"","–include=\"**/\"""–exclude=\"*\"""rsync.example.org::module""./mirror");
    pb.directory(directory);
    Process process = pb.start();
    int result = process.waitFor();

It works good, without any problem. But only on Windows. When I deployed the application on the Linux server, it synchronized all the files. It looked like that –exclude directive was simply ignored.

The weird thing was, that when I run the command from the shell it worked as it was supposed to run. The usual suspects were the quotes. Since the command worked, only some parameters were ignored, it was evident that the problem is subtle. I tried to replace double quotes with single quotes, put all parameters to one. I even tried to call the command using Runtime.exec(). It was just vain effort. (Runtime.exec() internally uses ProcessBuilder). The solution is simple. Just remove all the quotes from all parameters.



ProcessBuilder pb = new ProcessBuilder("rsync","-vtlr""–include=*.txt","–include=**/""–exclude=*""rsync.example.org::module""./mirror");
    pb.directory(directory);
    Process process = pb.start();
    int result = process.waitFor();

Like this, it works on both Linux and Windows.

One Response to “ProcessBuilder and quotes”

  1. Seth Tisue Says:

    The purpose of the quotes was to prevent characters like * from being interpreted specially by the shell. Only the shell sees the quotes; the shell strips them out before passing the arguments to the rsync command.

    But ProcessBuilder doesn’t use a shell; it runs the command directly. Since there’s no shell involved, the quotes aren’t needed, and if you include them, they will not be stripped out, causing the rsync command to become confused about your intentions.

    Why it would have worked on Windows with the quotes, I don’t know.

Leave a Reply