10

I am working on a script that will copy ONLY files that have been created within the last day off to another folder. The issue I am having is the script I have copies all of the files in the source directory instead of just the files less than a day old.

This is what I have:

find . -mtime -1 -exec cp --preserve --parents -a "{}" /somefolder \;

The above code copies all of the files in the source directory. If I remove all of the arguments for 'cp' then it works:

find . -mtime -1 -exec cp "{}" /somefolder \;

The above code copies only the newest files as I want but I need to preserve the attributes using the cp arguments.

I have also tried variables and for loops thinking maybe the -exec option was the issue:

files="$(find -mtime -1)"
for file in "$files"
do
cp --parents --preserve -a file /somefolder

However, the above for loop results in the same issue, all files are copied. If I echo $files only the files I need are shown.

How can I get this to work?

  • 1
    Ok I think I have it working using: find /sourcefolder -type f -mtime -1 -exec cp -a "{}" /somefolder \; – mac1234 Dec 12 '14 at 16:40
  • Wouldn't rsync be the better tool for this task instead of cp? rsync -a source destination – Darryl Aug 14 '18 at 22:36
7

Some implementations of cp have a -t option, so you can put the target directory before the files:

find . -mtime -1 -exec cp -a --parents -t /somefolder "{}" \+

Note that -a implies --preserve so I removed the latter.

3

You can use pax for this like:

pax -wrT "11$(date +%H%M)," . /destination/folder

The command-line bit-by-bit:

  • -wr - when pax is handed both -write and -read options it copies. Possibly also useful here. (but not included in the above command)

    • -link - which creates hard-links if at all possible rather than copying the file-data.

    • -X for restricting pax to the same source device and/or filesystem.

    • -s/src regex/replace/ - which modifies filenames in-stream

    • -verbose - for reporting on files sourced/targeted.

  • -T - the -Time option selects files for the target archive (or merely to copy when used with -wr) based on their /modification or inode /change (or both) times. It defaults to mod time. From...

man pax

  • ...Time comparisons using both file times is useful when pax is used to create a time based incremental archive (only files that were changed during a specified time range will be archived).

  • A time range is made up of six different fields and each field must contain two digits. The format is:

    [[[[[cc]yy]mm]dd]HH]MM[.SS]

  • Where cc is the first two digits of the year (the century), yy is the last two digits of the year, the first mm is the month (from 01 to 12), dd is the day of the month (from 01 to 31), HH is the hour of the day (from 00 to 23), MM is the minute (from 00 to 59), and SS is the seconds (from 00 to 59). The minute field MM is required, while the other fields are optional and must be added in the following order:

    HH, dd, mm, yy, cc

  • The SS field may be added independently of the other fields. Time ranges are relative to the current time, so...

    -T 1234/cm

  • ...would select all files with a modification or inode change time of 12:34PM today or later.

  • Multiple -T time range can be supplied and checking stops with the first match.

...so the 11 up there in my example command is relative to today - it is one less than today's date - which is the twelfth - and the rest is just a standard "$(date)" format followed by a comma.

...except - and the last thing worth mentioning - I use an absolute path for the target directory - and so should you if you do it. The docs all reference unspecified behavior for relative target paths - and the first time I ever tried using pax I was swearing under my breath for an hour in confusion with all of the weird results until I used an absolute path.

1

THanks everybody for the help, got it working using a combination of your suggestions:

went with the below code and it works perfectly.

find /sourcefolder -type f -mtime -1 -exec cp -a "{}" /somefolder \;

thanks again!

1

One can also select the exact date and time other than going back to certain amount of days

(This works well only in case your file names do not have any space, tab or wildcard in them)

cp `find . -type f -newermt '17 dec 2016 20:10:00'` FOLDER

Above copies all the files in the directory that were created after 17 december 2016 20:10:00 to the FOLDER (1 day before today :)

Be careful with the symbol for the find command, it is NOT this one: ' it is this, a backtick: ` date selection is with this: '

For files with spaces, tabs, newlines or wildcards in their names, you can use either of the solutions from Stéphane Chazelas, first is for GNU, second is for GNU or some BSDs:

find . -type f -newermt '17 dec 2016 20:10:00' -exec cp -t FOLDER {} + 
find . -type f -newermt '17 dec 2016 20:10:00' -exec sh -c 'cp "$@" FOLDER' sh {} +
  • 1
    You may want to read Why is looping over find's output bad practice? – Stéphane Chazelas Dec 18 '16 at 20:46
  • Thanks Stephane, that may be why I couldn't find this in any post, though for my case it worked like a charm. when you do this only find . -type f -newermt '17 dec 2016 20:10:00' – FatihSarigol Dec 18 '16 at 21:36
  • ... it prints the files created after that time, I am not sure what kind of issue it may cause itself. then I just use backticks to select these files to be copied. cheers – FatihSarigol Dec 18 '16 at 21:38
  • I believe the post you shared is about "Looping over", is my code looping over find's result? or is it just selecting find's result to be used by copy? (Sorry for 3 comments, I am apparently not allowed to edit my comments yet – FatihSarigol Dec 18 '16 at 21:41
  • 1
    Use find . -type f -newermt '17 dec 2016 20:10:00' -exec cp -t FOLDER {} + (GNU) or find . -type f -newermt '17 dec 2016 20:10:00' -exec sh -c 'cp "$@" FOLDER' sh {} + (GNU or some BSDs (the limiting factor wrt portability is the -newermt predicate here)). – Stéphane Chazelas Dec 18 '16 at 21:54
1

I was doing exactly same functionality but needed to preserve folder structure. Hence what I have done is a bit different.

cd sourcedir
find . -type f -mtime -$days -print0 | tar -czvf ${tarpath}/testtar.tar.gz --null -T -

where $days is number of days $tarpath is temporary path for storing these files. and when I wanted to restore.

cd $destdir
tar -xvzf ${tarpath}/testtar.tar.gz

That have done the trick for me.

Note: if you want to exclude some folder while taking backup you can use following command

find . -type f -mtime -$days ! -path '*/FolderToavoidSearch/*' -print0 | tar -czvf ${tarpath}/testtar.tar.gz --null -T -

Advantage : 1. I always had a copy of what I have restored last time in compressed format.

  1. also I have a pause in between restoration where I can go and check what are those files and if all ok then proceed with the script.

  2. It preserves the folder structure hence it just overwrited modified files from source directory into destination directory

Note : On the other hand if the requirement is not day limited I would use rsync

rsync -avz --exclude 'FolderToavoidSearch' --backup --backup-dir="/backup/dir/test/backup_$(date +\%Y-\%m-\%d)" /source/dir/ /dest/dir/

more for rsyc with date here

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.