Take the 2-minute tour ×
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.

This question already has an answer here:

I'm looking for a sequence of commands (one liner would be ideal) which will identify all the files created in particular year, and move the resulting files to another directory.

share|improve this question

marked as duplicate by slm Jul 21 at 14:23

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

3  
created (whatever that means), or last modified? –  Stéphane Chazelas Jan 22 at 12:23
6  
This question appears to be off-topic because it doesn't show any research effort. –  l0b0 Jan 22 at 12:25
    
What Unix variant? –  Stéphane Chazelas Jan 22 at 13:31
    
@l0b0, not any more than 80% the questions asked here. ITYM that it was not asked in a way/tone that is respectful of the potential answerers, but in itself, it's an interesting question, not that easy to answer in a portable and reliable way. –  Stéphane Chazelas Jan 22 at 13:37
    
@StephaneChazelas - did you want to try and salvage this Q&A? I think there is a kernel of a good Q in there, we'll have to edit it of course. I'm torn b/c I do not like to do all the work for the OP's but I also like to fill our site with interesting/useful Q&A's. –  slm Jan 22 at 14:06

4 Answers 4

With GNU or FreeBSD find (and possibly others), and assuming you mean to search on the last modification time:

y=2001
find . -type f -newermt "$y-01-01" ! -newermt "$(($y+1))-01-01" -exec sh -c '
  exec mv "$@" /dest/dir' sh {} +

Note that it would not include a file that was last modified exactly at 00:00:00.000000 on 2001-01-01, but would include one last modified at that time on 2002-01-01.

Another option with GNU tools:

y=2001
find . -type f -printf '%TY%p\0' | sed -zn "s/^$y//p" | xargs -r0 mv -t /dest/dir

With zsh:

autoload age
y=2001
mv -- **/*(D.e:age $y/01/01 $((y+1))/01/01:) /dest/dir

GNU and FreeBSD find also support looking at the birth time, but note that that time refers to when the inode was spawn (link count went from 0 to 1), it doesn't reflect the age of the content, or when that file was available by that name in the directory it is linked to, and not all operating or file systems support a birth time or a way to query it (Linux still doesn't as of 2014-01).

Note that the answers above do not check for potential file name collisions (for instance, ./foo/x and ./bar/x would end up overwriting each other).

share|improve this answer

this is one way of doing it:

src_dir=/tmp/in
target_dir=/tmp/out
year=2014

find ${src_dir} -maxdepth 1 -type f | while read f; do
  changed_in_desired_year=$(stat "$f" | egrep "Change:[ ]*${year}-")
  if [ -z "${changed_in_desired_year}" ]; then
    continue
  fi

  mv "$f" ${target_dir}
done

The interesting bit is the use of stat to get the changed/modified/access status of the file.

share|improve this answer
    
Note that -maxdepth is not a standard option to find. –  Stéphane Chazelas Jan 22 at 13:21
    
You forgot the -r option to read (will break on filenames containing backslashes), and to remove the whitespace characters from IFS (will break on filenames ending in those) –  Stéphane Chazelas Jan 22 at 13:22
    
Note that the stat command is not standard. There are several conflicting implementations. –  Stéphane Chazelas Jan 22 at 13:23
    
You seem to be assuming GNU stat here. Note that GNU find has the features of stat builtin (with -printf). Your code will only work in some English locales. In Spanish locales, you'd see Cambio:... for instance. –  Stéphane Chazelas Jan 22 at 13:24
    
find: bad option -maxdepth find: [-H | -L] path-list predicate-list –  user57369 Jan 22 at 13:25

edit: changed the timestamp of /tmp/begin, thanks to StephaneChazelas's comment

man touch #find how to create a "begin" file JUST BEFORE Jan 1st of the year at 00:00:00.000
          #and a "end" file for JUST AFTER the Dec 31st of the year, at 23:59:59.999
  #usually, -t time 
  #   specifies a particular time using this format:
  #        [[[[cc]yy]MM]dd]hhmm[.ss]

#make sure you place those 2 files OUTSIDE of the place where you look for files, as they are themselves suceptible to be moved!

touch -t 200901010000.00 /tmp/begin  #1st Jan of 2009 at 00h00mn00s (note: files with that exact time will be not included!)
touch -t 201001010000.00 /tmp/end    #just after Dec 31st of 2009

#then: with '/orig' the starting folder you want to look in, and '/dest' the destination folder:
find /orig \( \( -newer /tmp/begin \) -a \( ! -newer /tmp/end \) \) -exec echo mv '{}' /dest \;

#and remove "echo" once you know it's just listing the relevant files
share|improve this answer
    
Note that modern file systems have sub-second granularity, so newer(20081231235959) would include a whole second worth of files that shouldn't be included while newer(20090101000000) would exclude a microsecond worth of files that shouldn't be excluded. –  Stéphane Chazelas Jan 22 at 13:15
    
@StephaneChazelas: you're of course right, and it's good to warn about it... but it's easy to look for those files and see if they should be moved or not (before removing the "echo") ... And that's why I start the post with "man touch", as on the system I looked (an old AIX), touch only goes to the second ^^ ... (I believe the OS is more precise, though :/ So indeed the whole "touch" approach here may be flawed, or at least needs to be carefully looked at at the "edges"). The "echo" allows one to verify if this or that edge file is included or not, and adjust the "touch" accordingly. –  Olivier Dulac Jan 22 at 13:25
    
What I meant is that you don't need the extra complexity, touch -t 200901010000.00 would not be less correct. If you do touch -t 200812312359.59 begin, then why not touch -t 200912312359.59 end? –  Stéphane Chazelas Jan 22 at 13:30
    
@StephaneChazelas: ah ok, I understand. I'll indeed change that, as it's "less problematic" to just forget files specifically dated 0000.00, than to incorporate those made in the whole second before... –  Olivier Dulac Jan 22 at 15:18

Example :

 find . -type f -newerBt 2013-01-01 ! -newerBt 2014-01-01 | awk '{ print "mv " $0 " /dest/path/" }'

Source: https://stackoverflow.com/questions/158044/how-to-use-find-to-search-for-files-created-on-a-specific-date

share|improve this answer
    
-newerct checks the inode change time, it's not neither the file creation time or the age of the data as it is now in the file. Beare of what you do with the awk output. Don't pass it unchecked to sh as it could have dire consequences. –  Stéphane Chazelas Jan 22 at 12:57
    
@Stéphane, I think the file is being checked. As man says: -newerXY file ; In addition, if Y=t, then file is instead interpreted as a direct date specification. –  Quarc Jul 21 at 13:09
    
But the "c" is for inode change time, not creation (birth) time for which you need -newerBt (where available) –  Stéphane Chazelas Jul 21 at 13:13
    
Agree :) Will fix it here. –  Quarc Jul 21 at 13:18

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