Move files by date into different directory using CLI

321

Solution 1

Do not use ls. It's not recommended to use in such cases. Moreover using grep to filter according to date is not a good idea. You filename might itself contain 2012 string, even though it was not modified in 2012.

Use find command and pipe its output.

find . -newermt 20120101 -not -newermt 20130101 -print0 | xargs -0 cp -t /your/target/directory 

Here,

-newermt 20120101  ==>  File's modified date should be newer than 01 Jan 2012
-not               ==>  reverses the following condition. Hence file should be older than 01 Jan 2013
-print0 and -0     ==>  Use this options so that the command doesn't fail when filenames contain spaces 

Solution 2

If you have newer files on the old disk that you want to ignore I would go about it like this

  1. Create a temporary marker file with a modified-by date that separates files I want from those I don't
  2. Copy files older than the marker file to the new location

Here are sample commands for this, which assume you want to maintain any directory hierarchy from the old disk in the new (cpio is a copy command, similar to tar or pax):

touch -t 201201010000 /tmp/marker    # YYYYMMDDhhmm == Jan 1st, 2012
cd /path/to/old/disk
find . -type f \! -newer /tmp/marker -print0 | cpio -pmd0 /path/to/new/disk

Solution 3

I think maybe this issue is very the same as yours, you also can check this out: Create sub-directories and organize files by date

I write this new script based on that issue's first answer:

for x in *; do
  d=$(date -r "$x" +%Y)
  mkdir -p "/your/new/directory/$d"
  mv -- "$x" "/your/new/directory/$d/"
done
  1. write this script to a file named copy.sh in your old directory.

  2. replace the /your/new/directory with your new directory's path

  3. make this file executable with chmod +x copy.sh

  4. then execute this file by ./copy.sh

Solution 4

You probably should use a batch tool for batch operations. Doing so will usually entail reading/writing all records in a single stream rather than, for example, invoking a separate cp process for each file copied.

There is already a cpio answer written here, which, given only the options already provided you is likely what I would choose. However, the cpio format has been improved upon and folded into the standardized pax archive format since its heyday. The same is true of tar.

A strictly POSIX-pax will not likely provide any options for directly filtering archive members based on file modification times - though the standard does specify the %T list-mode format-modifier. Still, the most commonly available pax implementation that I know of - which is the BSD version maintained by mirabilos - does extend this into a directly accessible CLI-switch.

For example, to copy only all files in the tree rooted at ./ which were last modified before ccyymmddHHMM to /target/dir you could do:

pax -rwT,201301010000 ./ /target/dir

To avoid recursing into child directories you might do instead:

pax -rwdT,201301010000 ./* /target/dir

See the man page for more.

Share:
321

Related videos on Youtube

Erich Horn
Author by

Erich Horn

Updated on September 18, 2022

Comments

  • Erich Horn
    Erich Horn over 1 year

    I am looking into the Object.create to create a custom RegExp class. I want to use pure JS and not JQuery or other library. After spending time researching on MDN, here and other places, I find that my expectations and understand are still not quite adequate for my task.

    So far I have this:

    ( function ( SEAC ) {
        var _NativeRegExp = RegExp,
            _NativeRegExpProto = _NativeRegExp.prototype;
        SEAC.RegExp = function ( ) { _NativeRegExp.apply( this, arguments ); };
        SEAC.RegExp.prototype = Object.create( _NativeRegExpProto );    
    } )( self.SEAC || ( self.SEAC = {} ) );
    

    If I use it in the following code:

    var re = new SEAC.RegExp( "[aeiou]+", 'g' );
    var match = 'The quickening'.match( re );
    

    I get this response:

    TypeError: Method RegExp.prototype.toString called on incompatible receiver [object Object]

    I hope this the intention and question is clear enough.

    Anyone can explain to me what I am doing wrong and/or suggest how to do this? Or maybe my approach is not the best way, suggest another. I have done this before without using Object.create, but I wish to see if this is a better way to deal with inheritance and class creation.

    Why I want to do this is of course I want to customize the class and some of the native methods.

    • Felix Kling
      Felix Kling over 10 years
      According to the specification, you cannot apply methods of RegExp.prototype to objects that are not instances of RegExp: "a TypeError exception is thrown if the this value is not an object or an object for which the value of the [[Class]] internal property is not "RegExp"." es5.github.io/#x15.10.6 . So I guess it's not possible to inherit from RegExp.
    • Erich Horn
      Erich Horn over 10 years
      Hmmm.... that's to bad, I guess I will have to go back to an instance of a RegExp object inside of my custom RegExp and have each method applying that object method and then returning it, shame I have to wrap everything.
  • Erich Horn
    Erich Horn over 10 years
    Thanks Nick. That is tremendously insane. I experimented with making an instance from native RegExp from the same arguments in the constructor and returning that in toString and that also doesn't work, it won't throw, but it basically makes the regexp empty. That basically means your suggestion can work but with the limitation that toString can not be used in any useful way. thanks for the reply!
  • Nick Sharp
    Nick Sharp over 10 years
    Yeah, apparently RegExp plays crazy different from some of the other native Classes... its weird that it would, when you can do things with Array, Function and Object that you can't with RegExp... I played around with the making of a wrapper object that just in the constructor stores an internal reference to a RegExp instance and then just proxied the RegExp methods through... that seemed like the way to go. Still kinda derpy but functionaly clean
  • G-Man Says 'Reinstate Monica'
    G-Man Says 'Reinstate Monica' almost 9 years
    You might want to add some exception handling, so the script doesn't move itself into a 2015 directory.
  • Hagen von Eitzen
    Hagen von Eitzen almost 9 years
    Won't `-exec mv {} /your/target/directory \;' instead of '-print 0 | xargs -0 cp -t /your/target/directory' work just as good regarding problems with spaces in names? (Also, the OP wanted to move not copy)
  • shivams
    shivams almost 9 years
    ^^ Yes. Both achieve the same objective.
  • roaima
    roaima almost 9 years
    I guess I really ought to learn pax, but tar and cpio still stand me well. +1
  • mikeserv
    mikeserv almost 9 years
    @roaima - strictly speaking, while there is an actual pax archive format (which is an extension to the ustar format), the POSIX-spec'd pax utility reads/writes cpio, pax, and ustar formats. Because all three archive types amount primarily just to different means of encoding the metadata for many files alongside said files' actual data into a single stream, it isn't really too much of a stretch. I once wrote shitar - which was just a few lines of shell-script for - mostly dd - taring block devs on the fly based on the POSIX spec.
  • roaima
    roaima almost 9 years
    I like your linked script; strangely it would have been very useful a couple of months ago for exactly that same purpose. Oh well. I might even try to stop using cpio -H ustar ...