139

I'd rather not do this in PHP so I'm hoping a someone decent at shell scripting can help.

I need a script that runs through directory recursively and finds all files with last modified date is greater than some date. Then, it will tar and zip the file(s) keeping the path information.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278

9 Answers9

146

as simple as:

find . -mtime -1 | xargs tar --no-recursion -czf myfile.tgz

where find . -mtime -1 will select all the files in (recursively) current directory modified day before. you can use fractions, for example:

find . -mtime -1.5 | xargs tar --no-recursion -czf myfile.tgz
salezica
  • 74,081
  • 25
  • 105
  • 166
skrat
  • 5,518
  • 3
  • 32
  • 48
  • 4
    See user104848's answer below for how to deal with spaces in your file names – Brian Henk Jan 19 '11 at 16:28
  • 10
    Converting an arbitrary timestamp into a fractional, relative amount of time seems neither correct nor particularly convenient. The solution below using `-newermt` is *much* nicer. – Bobby Jack Oct 02 '12 at 14:59
  • 5
    When trying to extract any files with changes in a structure with directories, the directories themselves are marked modified causing the entire folder to be archived. Add `-type f` to only select files. This maintains the folder structure, but only backs up files with changes. – Brent Aug 26 '13 at 16:19
  • 1
    @BrianHenk user104848 changed their name, I'm pretty sure you mean [this answer from (currently) Jason Luther](http://stackoverflow.com/a/848609/327074) though – icc97 Apr 27 '16 at 21:16
  • 4
    The question asks to find files by an arbitrary date. This answer is how to find files by an arbitrary number of days in the past. I don't think this should be the accepted answer without adding a step to convert a date into a day delta. – Mark Oct 14 '16 at 13:14
  • For how to use a plain text date, see [below](https://stackoverflow.com/questions/848293/shell-script-get-all-files-modified-after-date#comment11129026_848327) – ᴍᴇʜᴏᴠ Mar 13 '20 at 08:53
  • big caveat: if xargs have to append "too many" files, it will invoke "tar ... -c..." multiple times, and thus will overwrite the previous invocations and you end up with only the last invocation's files in myfile.tgz. – Olivier Dulac Oct 29 '20 at 14:10
97

If you have GNU find, then there are a legion of relevant options. The only snag is that the interface to them is less than stellar:

  • -mmin n (modification time in minutes)
  • -mtime n (modification time in days)
  • -newer file (modification time newer than modification time of file)
  • -daystart (adjust start time from current time to start of day)
  • Plus alternatives for access time and 'change' or 'create' time.

The hard part is determining the number of minutes since a time.

One option worth considering: use touch to create a file with the required modification time stamp; then use find with -newer.

touch -t 200901031231.43 /tmp/wotsit
find . -newer /tmp/wotsit -print
rm -f /tmp/wotsit

This looks for files newer than 2009-01-03T12:31:43. Clearly, in a script, /tmp/wotsit would be a name with the PID or other value to make it unique; and there'd be a trap to ensure it gets removed even if the user interrupts, and so on and so forth.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 72
    Instead, you can use `-newermt '2009-01-03T12:31:43'` to avoid the need to create a file just for reference. – Michael Mior Jan 17 '12 at 17:43
  • @MichaelMior: Interesting - the 'find' on MacOS X 10.7.2 supports `-newermt` (documented under `-newerXY` since there are multiple options; X = m, Y = t in this case). The GNU find on the (almost archaic) Linux systems I use does not support the options, so it is a relatively recent arrival. Thanks for the heads up. – Jonathan Leffler Jan 17 '12 at 18:02
  • This option is present in GNU find 4.4.2 which I'm using on my system. – Michael Mior Jan 17 '12 at 18:19
  • It's not present in GNU find 4.2.27 which I'm using on one of my systems. So, that gives a window of GNU versions. MacOS X `find` does not support the `--version` option (or `-V`). – Jonathan Leffler Jan 17 '12 at 19:15
  • Great solution, but -newermt is much, MUCH nicer! :-) – Bobby Jack Oct 02 '12 at 14:57
  • 3
    Also note that GNU find supports relative times as well, ie. `-newermt '-2 weeks'`. – Cybolic Nov 23 '16 at 07:59
  • 1
    `-newermt '2009-01-03T12:31:43'` looks awesome, but sadly it seems to interpret everything in the wrong timezone: https://lists.gnu.org/archive/html/bug-findutils/2012-12/msg00009.html – antoine Feb 06 '18 at 02:43
  • @antoine: Curious, but there does seem to be a problem with time zones as reported. It is also curious that it hasn't been fixed in the 5+ years since it was reported. Thanks for the heads up! – Jonathan Leffler Feb 06 '18 at 07:25
  • In case anyone is stuck with that timezone issue, using the date format `Tue Jan 30 14:22:35 2018` instead of `2018-01-30T14:22:35` seems to solve the issue for me. No clue why though. – antoine Feb 06 '18 at 20:08
  • I guess `-newermt` is so relevant that it is worth editing the answer. – sancho.s ReinstateMonicaCellio Oct 22 '18 at 16:32
37

You can do this directly with tar and even better:

tar -N '2014-02-01 18:00:00' -jcvf archive.tar.bz2 files

This instructs tar to compress files newer than 1st of January 2014, 18:00:00.

one-liner
  • 791
  • 1
  • 9
  • 19
  • 9
    Huh... I've been using Unix since 1984 and never knew this. Always something to learn. – John Feb 11 '16 at 20:04
  • The implementations of `tar` that come with OS X and FreeBSD only support `--newer` which is the long option for `-N` in GNU `tar`. – nisetama Jun 07 '16 at 02:05
  • This is awesome... I could only get it to work with bzip, not using -xcvf and a gz extension... but I'm no expert. – phil Apr 21 '17 at 03:38
17

This will work for some number of files. You want to include "-print0" and "xargs -0" in case any of the paths have spaces in them. This example looks for files modified in the last 7 days. To find those modified before the last 7 days, use "+7".

find . -mtime -7 -print0 | xargs -0 tar -cjf /foo/archive.tar.bz2

As this page warns, xargs can cause the tar command to be executed multiple times if there are a lot of arguments, and the "-c" flag could cause problems. In that case, you would want this:

find . -mtime -7 -print0 | xargs -0 tar -rf /foo/archive.tar

You can't update a zipped tar archive with tar, so you would have to bzip2 or gzip it in a second step.

Jason Luther
  • 163
  • 1
  • 8
  • 1
    Regarding the second point, you can use a gzip-enabled tar command, like Gnu tar's -z option, to update zipped archives, too. – Suncat2000 Sep 07 '11 at 01:05
  • Or add the 'j' option to use bzip in recent GNU tars – hd1 Feb 22 '13 at 08:16
  • 3
    As I said above on Jonathan's answer, this will grab the folders which have changes causing all of their files to be imported. Add `-type f` to only select files. This maintains the folder structure, but only backs up the files with changes/added recently. – Brent Aug 26 '13 at 16:20
12

This should show all files modified within the last 7 days.

find . -type f -mtime -7 -print

Pipe that into tar/zip, and you should be good.

Chris Doggett
  • 19,959
  • 4
  • 61
  • 86
5

I would simply do the following to backup all new files from 7 days ago

tar --newer $(date -d'7 days ago' +"%d-%b") -zcf thisweek.tgz .

note you can also replace '7 days ago' with anything that suits your need

Can be : date -d'yesterday' +"%d-%b"

Or even : date -d'first Sunday last month' +"%d-%b"

Protagonist
  • 492
  • 1
  • 6
  • 17
Michel
  • 51
  • 1
  • 1
3

well under linux try reading man page of the find command

man find

something like this should

 find . -type f -mtime -7 -print -exec cat {} \; | tar cf - | gzip -9

and you have it

Luixv
  • 8,590
  • 21
  • 84
  • 121
3

You can get a list of files last modified later than x days ago with:

find . -mtime -x

Then you just have to tar and zip files in the resulting list, e.g.:

tar czvf mytarfile.tgz `find . -mtime -30`

for all files modified during last month.

mouviciel
  • 66,855
  • 13
  • 106
  • 140
2

This script will find files having a modification date of two minutes before and after the given date (and you can change the values in the conditions as per your requirement)

PATH_SRC="/home/celvas/Documents/Imp_Task/"
PATH_DST="/home/celvas/Downloads/zeeshan/"

cd $PATH_SRC
TODAY=$(date  -d "$(date +%F)" +%s)
TODAY_TIME=$(date -d "$(date +%T)" +%s)


for f in `ls`;
do
#       echo "File -> $f"
        MOD_DATE=$(stat -c %y "$f")
        MOD_DATE=${MOD_DATE% *}
#       echo MOD_DATE: $MOD_DATE
        MOD_DATE1=$(date -d "$MOD_DATE" +%s)
#       echo MOD_DATE: $MOD_DATE

DIFF_IN_DATE=$[ $MOD_DATE1 - $TODAY ]
DIFF_IN_DATE1=$[ $MOD_DATE1 - $TODAY_TIME ]
#echo DIFF: $DIFF_IN_DATE
#echo DIFF1: $DIFF_IN_DATE1
if [[ ($DIFF_IN_DATE -ge -120) && ($DIFF_IN_DATE1 -le 120) && (DIFF_IN_DATE1 -ge -120) ]]
then
echo File lies in Next Hour = $f
echo MOD_DATE: $MOD_DATE

#mv $PATH_SRC/$f  $PATH_DST/$f
fi
done

For example you want files having modification date before the given date only, you may change 120 to 0 in $DIFF_IN_DATE parameter discarding the conditions of $DIFF_IN_DATE1 parameter.

Similarly if you want files having modification date 1 hour before and after given date, just replace 120 by 3600 in if CONDITION.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291