Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I need to move files based on a year. I used the find command

find /media/WD/backup/osool/olddata/ -mtime +470 -exec ls -lrth {} \;|sort -k6

but for this command to successfully execute i need to know the exact mtime now 470 is just a guess. Means if I can give the year 2012 it gives me files only related to 2012.

So i need advice on how to

Find files based on year e.g 2012 and move them to other directory.

OS release 5.2

FIND version
GNU find version 4.2.27
share|improve this question
Does it make sense to use -exec ls ... \; instead of -exec ... +? Is your find too old for that? In that case find ... -print0 | xargs -0 ls... would be much faster. – Hauke Laging Apr 22 '13 at 13:27
I wish these questions (and answers) that deal with coreutils would routinely specify whether we're dealing with GNU or BSD (or other) utils. – labyrinth Jan 23 '14 at 17:44

You want to use the -newermt option for find:

find /media/WD/backup/osool/olddata/ -newermt 20120101 -not -newermt 20130101

to get all the files with modification time in 2012.

If your find does not support -newermt you can also do the following to prevent using offset calculations:

touch -d 20120101 /var/tmp/2012.ref
touch -d 20130101 /var/tmp/2013.ref
find /media/WD/backup/osool/olddata/ -newer /var/tmp/2012.ref -not -newer /var/tmp/2013.ref
share|improve this answer
-newermt flag is not available in Find command – OmiPenguin Apr 22 '13 at 12:56
That must be an old version of find that your RHEL comes with? I will provide an alternative in the answer for that – Anthon Apr 22 '13 at 13:03
Yes this one is 5.2 – OmiPenguin Apr 22 '13 at 13:05
I take it that is the revision of RHEL, not of find (I have find version 4.4.2) – Anthon Apr 22 '13 at 13:07
The newermt switch didn't show up in find until versions after v4.3.3, gnu.org/software/findutils/manual/html_mono/find.html. – slm Apr 22 '13 at 13:41

According to the man page, the argument to -mtime is the number of days you're looking for. You can use date +%j to find the number of days since January 1st of the current year.

share|improve this answer
Nice way. To be very "nitpicky" : -mtime -1 : is any file in the last 24hours. Not just the files from yesterday (or today). So, there will also be a little "overlap" : if you determine it's been 120 days since 2012, and today it is 15:45 when you launch the script, you'll end up selecting files up to dec 31 15:45 (and not the last ones of that day)... You can probably use: nb_day - 1, and then "weed out" the few ones who dates from 2013 (those could be found by a ls -l | grep -v, BUT the output differ if they are 1 day old only... lots of pitfalls...) – Olivier Dulac Apr 22 '13 at 12:53
You do want to use the -daystart option if you are going to work with -mtime. Otherwise you will have problems with files around the beginning and end of the year whatever way you turn unless you run this exactly at midnight. You can do the offset more accurately with -mmin than with -mtime if you can find the number of minutes since the new year easily. But the same problem exists with that as with -mtime, just for fewer files (those one minute around midnight newyear). – Anthon Apr 22 '13 at 13:49
Yeah, re-reading the man page I am seeing how it breaks it down to hours so doing a simple find -mtime $("date -+%j") probably won't give the OP what they're going for. I'm leaving it up for posterity though since this seems like a possible blindspot for people to fall into. – Bratchley Apr 22 '13 at 15:03
touch --date=2011-12-31T23:59:59 start
touch --date=2012-12-31T23:59:59 stop
find / -newer start \! -newer stop -printf %Tx" "%p\\n

-exec ls doesn't make any sense.

share|improve this answer
-exec ls -l makes more sense, and even more while testing. – Michael Kjörling Apr 22 '13 at 13:17
@MichaelKjörling find can print everything that ls can. OK, with one exception: escaping / quoting of unpleasant chars. But in general the output of find can be sorted directly. Useless calls of ls don't make the whole thing faster. – Hauke Laging Apr 22 '13 at 13:28
I very often use something quite similar (although personally I prefer -print or possibly -ls) while testing. The advantage of using -exec ls {} is that it already executes something external to find. So by the time you switch from ls to mv, the actual changes are minimal. – Michael Kjörling Apr 22 '13 at 13:31

You can try to use a combination with the stat and/or date commands as in the following one-liners:

BSD / Mac OS X:

find . -type f -print | while read file; do eval `stat -s "$file"`; year=`date -jf "%s" "+%Y" "$st_mtime"`; dest="/path/to/destination/$year; mkdir -p "$dest"; mv "$file" "$dest"; done


find . -type f -print | while read file; do year=`date -r "$file" "+%Y"`; dest="/path/to/destination/$year; mkdir -p "$dest"; mv "$file" "$dest"; done

In both cases the approach is to use the date command to extract the year from the last modification time of every file and then to construct a path with this year. The command mkdir -p will create this path if it doesn't exist already. Of course you can use some other find options to refine your search.

share|improve this answer

If you do this from the working directory, you can do this instead:

ls -l |awk '{ if ($8 == "2013") print $9 }'

This simplifies things considerably and doesn't cause any overlap. But it also assumes that these files are older than 6 months old, and that ls will print the year instead of the exact time.

For files newer than 6 months old, you'll just have to replace it with this:

ls -l |awk '{ if ($6 == "May") print $9 }' 

or something similar, depending on the month. If you want to create a list of months to move files for (or if you want to create a list for years) do this:

month="May June July"; 
for i in `echo $month`; 
    for j in `ls -l |awk '{ if ($8 == "'$i'") print $9}'`
        mv $j $dest;
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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