I have lots of shell aliases/functions for repetitive tasks. Copying files to and from servers, removing editor backup files, connecting to specific databases, the list goes on.

Sometimes however the thing I want to do is directory specific. A good example of this is when I’m developing scripts. Typically, I edit in the comfort of my desktop, and copy scripts to the server for testing. As I’m often working on multiple files, I use rsync to keep the remote directory in sync.

1
2
3
# Edit
rsync -av . example.com:some/directory/path
# Test

This keeps the local and remote directories in sync, uploading only the files that have changed. There are other work-flows I could use, for example, my editor supports remote editing with SSH, but rsync works for me.

I’m lazy, and don’t want to have to type out the rsync command or even find it in my history. Normally, I’d reach for an alias, but each project has a different target host and/or directory.

So instead, I reach for Make. The short version is that given a Makefile in the current directory running make will cause commands in that file to be run. Make is about as old-school as it gets, if you have a compiler installed you have Make, this setup works just about anywhere.

The Make syntax is Turing complete, but for this simple example we just need the name of a target and the command we want to run:

1
2
3
.PHONY: sync
sync:
  rsync -av . example.com:some/directory/path

Since we have only one rule, the name doesn’t matter. The first rule in a Makefile the default, so that’s what’s going to run when we type make.

One slight bit of complexity. Make’s true job in life is to create/update the target, which is expected to be a file. It checks if the target is older than it’s dependencies (if any) and runs the command only if the target needs updating. .PHONY sync tells Make that the target isn’t a real file. We need this so Make will run the command if a file with the name of our rule happens to exist in current directory.

If you are a Ruby developer, you also have Rake and can use it instead by creating a Rakefile:

1
2
3
task :default do
  sh 'rsync -av . example.com:some/directory/path
end

Unlike Make, Rake requires you to have an explicit default task, which you can do by calling it default or by creating an alias in the form of task default: :sync. Also unlike Make, Rake doesn’t treat targets as files in needs to create, unless you tell it to (and that’s another show).

There is no advantage to using Rake over Make, go with what you are comfortable with.

Of course in keeping with my lazy streak, I have a function to the create the Makefile.

1
2
3
4
5
function setup-rsync() {
    if [ ! -f Makefile ]; then
     printf ".PHONY: sync\nsync:\n\trsync -av . $@\n" > Makefile
    fi
}

Now I can just run setup-rsync example.com:some/directory/path once and make from then on. Laziness for the win!

Comments