I need to edit PHP files on an FTP server and since my local editor is unreliable when saving to a GVFS mount, I let rsync do the synchronization:

while true
    inotifywait -r -e create -e modify -e close_write -e moved_to ./ | \
    mawk '{ print $1 }' | \
    while read f
        # currently, $f is always a directory (not just the changed file)
        echo "rsync $f..."
        mkdir -p $webroot"$f"
        rsync --exclude "*/" -rlpgoD "$f" $webroot"$f"

That script synchronizes directories the files of which changed, but it is damn slow. That is why I seek an improvement.

How would you write such a script? Ideally it does not synchronize an entire directory but just the changed file.

  • Can you ssh/scp rather than FTP? vim scp://host.example.com//path/to/file is a wonderful thing. Another alternative would be to put your PHP files into an SVN or git repository, edit locally, and then just grab the updates from source control on the remote host. – DopeGhoti Jun 18 '16 at 21:42
  • Usually I prefer SFTP, but this is not offered by the server (nor source control) which solely provides me with FTP access (the server was not my choice). Thus I need to improve my synchronization performance via GVFS mount. – ideaboxer Jun 18 '16 at 21:52

If you have the space, you could keep a local copy of the remote hierarchy. When your inotify triggers due to a change in your real hierarchy you can use rsync -a -i between the real and local copy to update it and generate a list of actual changes. Apply just this list to rsync update the remote from the local copy.

To help with this scenario, see the rsync man page BATCH MODE section. Instead of the -i you do rsync -a --write-batch=foo between the real and local copy, then do rsync -a --read-batch=foo to the remote to apply exactly the same changes. (The foo file is a binary file containing a copy of all the changes).

Here's an example in /tmp using dirs a, b, and c, where a is your real directory where you edit files, b is a local cached copy of the remote, and c is the remote. We create a and copy it to b and c to start with. I've put c in a variable so it can be changed later.

cd /tmp || exit
echo do: rm -fr a b c foo foo.sh
mkdir a
echo hi >a/f1
echo hi >a/f2
rsync -av a/ b
rsync -av a/ "$c"

We have 3 identical directories. We edit dir a.

echo bye >>a/f1
echo bye >>a/f3
rm -f a/f2

We rsync a to b, create a batch file foo:

rsync -av --delete --write-batch=/tmp/foo a/ b

We can now rerun the changes saved in foo on c:

rsync -av --delete --read-batch=/tmp/foo  "$c"

There are now again 3 identical directories. The advantage is that rsync will only do the updates it recorded in the foo file. I tried this using a local ftp gvfs mount for c, but it didn't work (c="$XDG_RUNTIME_DIR/gvfs/ftp:host=localhost,user=ftp/test/"). The gvfsd-fuse mount seems very buggy and assumes sometimes that a remote file should be a directory, so rsync never worked with it.

|improve this answer|||||
  • Can you post an example? Actually, I am working with a local copy otherwise the script I posted was useless. – ideaboxer Jun 19 '16 at 8:48
  • I spent some time trying to get an example to work using a local ftp server, but rsync would not work well with gvfsd-fuse (on fedora 22, not using gnome). Perhaps you'll have more luck. I updated my answer. – meuh Jun 19 '16 at 14:40

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.