I have a versions/ directory on a remote server to which I have only rsync daemon and ftp access. This directory contains a set of subdirectories, each named after the datetime of a deployed codebase (e.g., versions/20150101000000/, versions/20150102120000/, etc.). I need to automate deleting old versions, and my intuition is that an rsync with an empty source directory will be much faster than recursively iterating with ftp (I've verified I do not have ftp's SITE EXEC available to do a simple rm -rf versions/$version/).

I am using an initial rsync --list-only command to parse the list of versions, sorting them (I've seen evidence that rsync doesn't always return the list in expected order), and then choosing to delete all but the most 3 recent versions.

The command to empty a specific directory is straightforward:

rsync -vr --delete `mktemp -d`/ rsync://user@host:123/module/versions/$version/

However, in expected rsync fashion, this will not delete the top-level directory itself. Is there a way with rsync to request that the directory being synced be removed in addition to its contents? Otherwise, I suspect it should be possible to run the sync against the parent versions/ directory with some combination of --exclude/--include/--filter arguments, but for the life of me I cannot figure it out.

I've tried things like:

rsync -vr --delete --include=/20150101000000/ rsync://user@host:123/module/versions/

with and without either slash, with and without an --exclude='*' listed before or after the --include arguments, as well as with --delete-excluded in the event that matching both the --include and --exclude arguments requires it. Nothing seems to be achieving my desired results.

I could have already completed the task by doing the rsync to empty the contents, followed up with an ftp rmdir on the empty directory, but I am stubborn enough to know that this is possible with rsync alone and so will hope for a solution. Thanks!


Stubborn is good. I stopped when the following worked, tested with local files not rsync://. Use -n to not do it, -iv to see why it does it. empty is your local empty dir. The remote dir to delete, 20150101000000, has to be empty too.

rsync -nivd --delete --filter='-! /20150101000000' empty/ rsync://user@host:123/module/versions/
  • I won't mark as accepted yet, as I wait for other comments and try some more variations myself to manage the deletion of an entire remote directory with a single command. It must be possible! – user86616 Sep 7 '15 at 22:36

Thanks to a friendly IRC contact, I've found a working solution to delete a specific directory using a single rsync command. It works by specifying an --include argument for the contents of the directory (--include '/20150101000000/**'), a separate --include for the directory itself (--include '/20150101000000/'), and the --exclude '*' to ignore all other contents of the top-level directory (in this case, versions/):

rsync -vr --delete --include '/20150101000000/**' --include '/20150101000000/' --exclude '*' `mktemp -d`/ rsync://user@host:123/module/versions/

I then went digging into the man page in an attempt to fully understand the above, and came across this handy section:

a trailing "dir_name/***" will match both the directory (as if "dir_name/" had been specified) and everything in the directory (as if "dir_name/**" had been specified). This behavior was added in version 2.6.7.

This information allows us to simplify to a single --include argument:

rsync -vr --delete --include '/20150101000000/***' --exclude '*' `mktemp -d`/ rsync://user@host:123/module/versions/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy