rsync --delete --files-from=list / dest/ does not delete unwanted files

dAnjou picture dAnjou · Nov 28, 2009 · Viewed 17.7k times · Source

As you can see in the title I try to sync a folder with a list of files. I hoped that this command would delete all files in dest/ that are not on the list, but it didn't.

So I searched a little bit and know now, that rsync can't do this.

But I need it, so do you know any way to do it?

PS: The list is created by a python script, so it is imaginable that your solution uses some python code.

EDIT, let's be concrete:

The list looks like this:

/home/max/Musik/Coldplay/Parachutes/Trouble.mp3
/home/max/Musik/Coldplay/Parachutes/Yellow.mp3
/home/max/Musik/Coldplay/A Rush of Blood to the Head/Warning Sign.mp3
/home/max/Musik/Coldplay/A Rush of B-Sides to Your Head/Help Is Around the Corner.mp3
/home/max/Musik/Coldplay/B-Sides (disc 3)/Bigger Stronger.mp3

and the command like this:

rsync --delete --files-from=/tmp/list / /home/max/Desktop/foobar/

This works, but if I delete a line, it is not deleted in foobar/.

EDIT 2:

rsync -r --include-from=/tmp/list --exclude=* --delete-excluded / /home/max/Desktop/foobar/

That works neither ...

Answer

SimonJ picture SimonJ · Nov 28, 2009

Perhaps you could do this using a list of include patterns instead, and use --delete-excluded (which does as the name suggests)? Something like:

rsync -r --include-from=<patternlistfile> --exclude=* --delete-excluded / dest/

If filenames are likely to contain wildcard characters (*, ? and [) then you may need to modify the Python to escape them:

re.sub("([[*?])", r"\\\1", "abc[def*ghi?klm")

Edit: Pattern-based matching works slightly differently to --files-from in that rsync won't recurse into directories that match the exclude pattern, for reasons of efficiency. So if your files are in /some/dir and /some/other/dir then your pattern file needs to look like:

/some/
/some/dir/
/some/dir/file1
/some/dir/file2
/some/other/
/some/other/dir/
/some/other/dir/file3
...

Alternatively, if all files are in the same directory then you could rewrite the command slightly:

rsync -r --include-from=<patternlistfile> --exclude=* --delete-excluded /some/dir/ dest/

and then your patterns become:

/file1
/file2

Edit: Thinking about it, you could include all directories with one pattern:

/**/

but then you'd end up with the entire directory tree in dest/ which probably isn't what you want. But combining it with -m (which prunes empty directories) should solve that - so the command ends up something like:

rsync -m -r --delete-excluded --include-from=<patternfile> --exclude=* / dest/

and the pattern file:

/**/
/some/dir/file1
/some/other/dir/file3