5

So i'm trying to use the find command to find all files in my system with mtime -x. It does this but it does not "find" the directories of the file.

find . -mtime -2 -exec rsync -av {} /destination/ \;

I thought if i could bring over all the directories that it would feed into them if it could so i tried:

rsync -a -f"+ */" -f"- *" source/ destination/

Which works a charm for bringing over the directory tree but when i try to pull the files into it, they don't go into the separate directories, they just spill into the main directory i copied them into to.

Any ideas how i can get either the find command to find the directories too or another way around this problem?

user768352
  • 53
  • 1
  • 1
  • 3
  • Did you try `rsync -avR` instead of `rsync -av`? This should replicate the whole path on the destination. – Dubu Mar 11 '14 at 12:22
  • @Dubu I just tried and it seems to copy the whole folder, regardless of `mtime` :o – user768352 Mar 11 '14 at 13:07
  • Hm. You should probably add `-type f` to your `find` command, so only files will be considered for transfer: `find . -type f -mtime -2 -exec rsync -avR '{}' /destination/ \;` – Dubu Mar 11 '14 at 13:20
  • "So only files will be considered for transfer" - but i want directories transferred too, unless you mean i should run `rsync -a -f"+ */" -f"- *" source/ dest/` before doing `find . -type f -mtime -2 -exec rsync -avR '{}' /dest/ \;` ?? @Dubu – user768352 Mar 11 '14 at 14:21
  • Nevermind! I tried it and it worked a treat! thanks. (do you wanna compile that into an answer and i'll mark it as sovled? or i can put it as an answer) – user768352 Mar 11 '14 at 14:22
  • I will compile an answer. – Dubu Mar 11 '14 at 14:32

1 Answers1

7

There are two issues with this command line:

find . -mtime -2 -exec rsync -av {} /destination/ \;`

Transferring path names

First, when giving (single) file names to rsync and not simply a directory, it must be told explicitly to use the whole path and not only the filename for the destination. For this, use the option -R. From the manual page to rsync(1):

-R, --relative Use relative paths. This means that the full path names specified on the command line are sent to the server rather than just the last parts of the filenames. This is particularly useful when you want to send several different directories at the same time. For example, if you used this command: rsync -av /foo/bar/baz.c remote:/tmp/ ... this would create a file named baz.c in /tmp/ on the remote machine. If instead you used rsync -avR /foo/bar/baz.c remote:/tmp/ then a file named /tmp/foo/bar/baz.c would be created on the remote machine, preserving its full path. These extra path elements are called "implied directories" (i.e. the "foo" and the "foo/bar" directories in the above example). [...]

The manpage then continues on how to manipulate the path so that only parts of it will be present on the receiving side, but that is out of scope here.

Search for files only, not for directories

Second, find called as above will not only report files, but also directories. When a directory name is given to rsync as a source, it will synchronize that whole directory to the destination. This can be prevented using the additional test -type f ("type must be file") for find. Be aware, though, that this will not only exclude directories, but also sockets, named pipes, block and char devices, and symlinks. For symlinks, you could use the -xtype parameter instead, which will check the type of the symlink target.

Solution

So, the modified command line would look like this:

find . -type f -mtime -2 -exec rsync -av -R {} /destination/ \;

This will find all files (-type f) in the current path (.) that have been modified within the last two days (-mtime -2) and for each of them: execute (-exec) rsync, copying the file with the given name ({}) to /destination/, preserving most attributes (-a), giving verbose output (-v) and reproducing the whole path at the destination (-R).

Dubu
  • 611
  • 3
  • 12