I store backups of databases in a directory structure


an example would be

basics_mini/2012/11/05/012232/RATIONAL.0.db2inst1.NODE0000.20110505004037.001 basics_mini/2012/11/06/012251/RATIONAL.0.db2inst1.NODE0000.20110505003930.001

note that timestamp from the backup file cannot be used. Before the automation testing starts the server time is set to 5.5.2011

So the question is how I can get the latest file if I pass the "base directory" (basics_mini) to some function that I am going to code.

I need to restore the newest database. I do that in php but I wonder if there is a simple shell scripting solution.

find 'basics_mini' -type f | 
sed 's/.*basics_mini\///' |
sort -t '/' -k1nr -k2nr -k3nr -k4nr |
head -1

This will find files in your backup directory, then sed will strip the leading path (up until your year dir). Then, the sort will separate the pathname on '/' and perform a numerical sort on field 1, 2, 3 and 4, i.e., year, month, day and time. Finally, head -1 will return the top line of output.

Of course, this will only return 1 file even if there were multiple identical newest entries (if that's a concern for you).

  • Works flawlessly. Great explanation. Thank you. PS one file is good enough because it is basically imposible to have two backups created at the same time (second wise) – Radek Nov 9 '12 at 0:26
  • 1
    I don't see any advantage of removing the leading path with sed, nor by splitting the fields in the sort nor by sorting numericallly. nevertheless I learned how to use sort with different fields. – miracle173 Nov 11 '12 at 8:02
  • @miracle173 The advantage being that it works in more cases than a raw sort of the input would. – tojrobinson Nov 11 '12 at 23:54

find should suit your needs:

find "/path/to/backup_dir" -type f|sort -r|head -n1

This only works if you've got (as in your example) leading zeroes on your month and day folders

If you want a backup with a specific file name (or pattern) add a name pattern to the find parameters, e.g.

find "/path/to/backup_dir" -type f -name "*db2inst1*"|sort -r|head -n1

... or use -iname for case insensitive patterns

Now to the details of the above commands:

  • find "/path" recursively lists all files/dirs in the given path (unless you use further filtering:
  • the -type f parameter of find filters out everything that's not a regular file)
  • -name or -iname match files according to a specific pattern
  • sort sorts the output in reverse order (-r)
  • head -n1 only prints the first line (-n 1) of its input and immediately exits after doing that.
  • Somebody downvoted this answer. Why cannot you say why? – Radek Nov 8 '12 at 23:52
  • 3
    This will not sort the files as intended. The numeric sort is not effected at any point, let alone for each field that you want to sort by, i.e., you will get a file with month 3 being newer than one with month 10 . – tojrobinson Nov 9 '12 at 0:25
  • You're right... @tojrobinson. But the examples in the original question all have leading zeros for months/days. So this will only become a problem in the year 10000 (as in your last example) – mreithub Nov 9 '12 at 0:34
  • The problem will occur in October next year :-) – Radek Nov 9 '12 at 1:07
  • @Radek: no, not in October next year, in the year 10000. – miracle173 Nov 11 '12 at 9:17

With this naming scheme, the most recent backup is in the last subdirectory in lexicographic order. You can obtain the most recent directory directly in the shell, taking advantage of the fact that wildcards are expanded in lexicographic order.

cd basics_mini
set [0-9][0-9][0-9][0-9]/*/*/*
shift $(($#-1))
echo "The most recent backup is in $1"

In zsh, you can directly get the last directory with a glob qualifier.

echo "The most recent backup is in" basics_mini/[0-9][0-9][0-9][0-9]/*/*/*([-1])

My solution would be to use this. It will output the newest file possible:

ls -lcR --full-time | grep '^-' | sort -k 6 -r | head -n 1


ls -lcR

-l use a long listing format

-c show ctime (time of last modification of file status information)

-R list subdirectories recursively

grep for files starting with a - (dash), meaning 'regular-files'.

sort -k 6 -r

-k Sort by column n (6 as this holds the date field)

-r Reversed

head -n1

-n number of rows to display (from the top down. 1)

  • I don't have time to try any more. But your code doesn't work. I tried to not to 'reverse' the sort and it looked ok. – Radek Nov 9 '12 at 0:29
  • I've moved the -r to after the -k in sort in my answer. Now it works. my fault. Changed the command without testing. silly me. – delh Nov 9 '12 at 0:36
  • I think the -r is not necessary at all. – Radek Nov 9 '12 at 1:06
find -maxdepth 1 -type ['d' for directory or 'f'for file] | ls -t | head -1 .. 

This should work.

  • this looks only in the current directory and avoid its sub-directories.. if you dont want that takeoff the maxdepth option – arun Feb 27 '14 at 18:05
  • piping find results into ls has no effect what's-so-ever, the two dots at the end also cause a syntax error, this answer simply will not run. – X Tian Feb 28 '14 at 0:50

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.