Howto rollover a file when size exceeds using unix find

Here is a one liner to rollover a file to file.old when it exceeds the size using find command. Lets say we have a script in cron that runs and prints messages in a log file. Overtime the log file will grow and we would want to rollover the log file to log.old. Many solutions exist by finding the size and comparing it. Here is one elegant solution in one liner. Thanks to my colleague Vlad who gave the idea for using find and exec, and I added the automatic substitution or brace expansion from my knowledge-base. Happy sharing of knowledge.

find /var/log/ -name myapp.log -size +1M -exec mv {}{,.old} ;

Explanation

This means that we are finding log file with name myapp.log in /var/log directory, and if its size exceeds 1MB we are asking it to be moved to myapp.log.old. manpage for find also describes that you can use various keywords for the size (e.g. b = 512 byte blocks, c = bytes, M = MB, G = GB etc.).

The important part here is the exec command (described in an old post here) where we are using mv and also the brace expansion for automatic substitution (described in an old post here). First pair of curly braces which are escaped using / are expanded by find command to fill in the filename (see man page for find and search for -exec). That results in mv /var/log/myapp.log{,.old} which is equivalent to mv /var/log/myapp.log /var/log/myapp.log.old.

OS Interoperability

Some OS may not allow the proper expansion of braces. So the safe bet would be to only make use of -size and -exec without the expansion. For example, following is the equivalent of the command that I provided earlier.

find /var/log/ -name myapp.log -size +1M -exec mv {} /var/log/myapp.log.old ;

OR in a script setting

find $LOGDIR -name basename `$LOGFILE` -size +1M -exec mv {} $LOGFILE.old ;

Lets see it in action.

unixite@sandbox:~> ls -l /var/log/myapp.log
-rw-------  1 unixite unixite 40562865 2011-03-27 12:15 /var/log/myapp.log
unixite@sandbox:~> find /var/log/ -name myapp.log -size +30M -exec mv {}{,.old} ;
unixite@sandbox:~> ls -l /var/log/myapp.*
-rw-------  1 unixite unixite 40562865 2011-03-27 12:15 /var/log/myapp.log.old
unixite@sandbox:~>
  • Adam Grumet

    Hello,

    I am trying to perform a brace expansion within a find command to better automate the files I am searching for. For example, if I would like to find (and ultimate perform an operation on) all the .dat and .txt files, I would think that the following command would work:

    find . -name ‘*.{dat,txt}’ -exec ….

    But no such luck. No files are found. Whereas:
    find . -name ‘*.dat’
    find . -name ‘*.txt’
    work fine. But obivously, I would like to expand this list for real life purposes.
    BTW, I am using CYGWIN.

    Much thanks,
    Adam

    • Thanks for the question Adam. To answer your question, I have posted the solution to http://www.theunixtips.com/bash-search-multiple-file-patterns-using-single-find-command. Basically you have to use “-o” and/or “-a” switches with find command. So to answer your question, you have to use find . -name "*.dat" -o "*.txt" -exec .... I do not have cygwin so not very sure if this will work there, but it will work on most major UNIX variants. I have tested and confirmed on Solaris and Linux.