Programming, Ruby

Date and Shell Find in Ruby

I was writing a small script to do backups on my local machine. Before this I was doing backups manually. To make this easier I came up with a naming scheme, with a dream to automate this.

Today the dream came true.

The scheme is really simple: Distinct_name_for_a_resource-DATE[-comment].(tar.gz|7z)
DATE is of format YYYYMMDDHHSS – no separators.

Sorting is really easy.

That’s the background. The tool finds if there have been any modified files in the directory being backed up and backs up the whole thing if so (no incremental backups). I wanted to use find as the tool for searching. Imagine my surprise when I could not find the key to give find a date for comparison.

There are keys of type -mtime and -mmin, which are relative to current time and specify an offset in days and minutes respectively. But I wanted a date.

It is possible of course to use -newer flag, which takes a filename and finds all, which are newer than that. It is possible to create a file with a specific date with

`touch -d DATE filename`
output = `find PATH -newer filename`
if (output.size > 0)
  # you found something
end

However, there is a better solution. It is not really convinient when using from command line – it involves some computation. In this particular case, I use find inside a script, therefore it is perfectly appropriate.Reinventing the wheel is not an option – takes too much time to write and run. It would be relatively easy to write a ruby-based traversal with this single test. If not for the fact that I love to backup large quantities of files and really hate waiting. So let’s use find – it is implemented in C with lots of optimisations – should work faster than some ruby code comparing ruby date objects. It is quite easy:


tnow = Time.now
last_archive =~ /(#{prefix}-)([0-9]{12})([-.].*)/
puts "Found last backup: #{last_archive}"

time = get_time_from_string($2) # converts the 12 char string to Time obj

# Convert to minutes
minutes = ((tnow - time) / 60.0).floor

# Search
out = `find #{path} -mmin -#{minutes}`
archive_it = out.size > 0
puts "Files were modified" if archive_it

And that is it, no rocket science. Note, that one needs to use ‘-#{minutes}’ to tell find to use <= operator rather than just == without the ‘-‘.Why not use DateTime if we need both the date and the time? Apparently the performance of DateTime is much worse than Time, and they have the same functionality.

Standard

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s