5

I have a folder where I backup my databases to and I want to delete all backups created between 11 am and 3 pm and it doesn't matter what day it is -- this is the catch!

I found this command to be very helpful, but not in my use case:

find . -type f -newermt '01 nov 2018 00:00:00' -not -newermt '10 nov 2018 00:00:00' -delete

But here it forces me to an interval between two dates! I want to delete only backups created between two specific times.

4
  • @Goro no i didn't. Commented Sep 12, 2018 at 12:56
  • The answer for a possible duplicate it would remove files that were modified in the last $hours. Commented Sep 12, 2018 at 13:31
  • 3
    Correct! I just meant that you add this note to the comments not to re edit the question ;-)
    – user88036
    Commented Sep 12, 2018 at 13:32
  • See this answer on Super User. Commented Sep 12, 2018 at 15:10

2 Answers 2

5

Simply enough, given that you tagged , you have the stat command available, which will extract a file's modification time, and the GNU date command, which will extract the hour from from a given time:

find . -type f -exec sh -c '
  h=$(date -d @$(stat -c %Y "$1") +%-H); [ "$h" -ge 11 ] && [ "$h" -lt 15 ]' \
  sh {} \; -ls

If the results look correct, then:

find . -type f -exec sh -c '
  h=$(date -d @$(stat -c %Y "$1") +%-H); [ "$h" -ge 11 ] && [ "$h" -lt 15 ]' \
  sh {} \; -delete

Here's a test-run with the -ls version:

$ touch -d 'Wed Sep 12 11:00:01 EDT 2018' 11am
$ touch -d 'Wed Sep 12 12:00:02 EDT 2018' 12pm
$ touch -d 'Wed Sep 12 15:00:03 EDT 2018' 303pm
$ find . -type f -exec sh -c 'h=$(date -d @$(stat -c %Y "$1") +%-H); [ "$h" -ge 11 ] && [ "$h" -lt 15 ]' sh {} \; -ls
1705096    0 -rw-r--r--   1 user group 0 Sep 12  2018 ./11am
1705097    0 -rw-r--r--   1 user group 0 Sep 12  2018 ./12pm

Credit to Kusalananda for writing the excellent answer I followed, at: Understanding the -exec option of `find`

Note that we do not want the {} + version of find here, as we want the -exec results to be per-file, so that we only delete files that match the time range.

The embedded shell script has two main pieces: determine the file's "hour" timestamp and then return success or failure based on the range. The first part is itself accomplished in two pieces. The variable is assigned the result of the command substitution; the command should be read inside-out:

  1. $(stat -c %Y "$1") -- this (second) command-substitution calls stat on the $1 parameter of the embedded shell script; $1 was assigned by find as one of the pathnames it found. The %Y option to the stat command returns the modification time in seconds-since-the-epoch.
  2. date -d @ ... +%-H -- this takes the seconds-since-the-epoch from the above command substitution and asks date to give us the Hours portion of that time; the @ syntax tells date that we're giving it seconds-since-the-epoch as an input format. With the - option in the date output format, we tell GNU date to not pad the value with any leading zeroes. This prevents any octal misinterpretation later.

Once we have the $h Hour variable assigned, we use bash's conditional operator [[ to ask whether that value is greater-than-or-equal to 11 and also strictly less than 15.

6
  • 3
    indeed, thumb up to @Kusalananda!!!
    – user90704
    Commented Sep 12, 2018 at 13:17
  • Your answer is correct, i've tried it but it give me error output between the files >>> sh: line 1: [[: 09: value too great for base (error token is "09") does it make a problem? Commented Sep 12, 2018 at 13:18
  • 3
    @Jeff Schaller. May I kindly ask you to explain, for a newbie like me, what @$(stat -c %Y "$1") more specifically @$ and 10# means!?
    – user308606
    Commented Sep 12, 2018 at 13:27
  • 1
    Thank you, It would be helpful to explain like @kasper said. Commented Sep 12, 2018 at 13:30
  • 4
    @Kasper & Ismail, see the edit
    – Jeff Schaller
    Commented Sep 12, 2018 at 13:37
0

Not ideal, but this might be useful.

find . -type f -print | while read l; do
    hour=$(stat -c "%z" ${l} | awk '{print $2}' | awk -F: '{print $1}')
    if [[ 11 -le ${hour} ]] && [[ ${hour} -le 15 ]]; do
      rm -f ${l}
    done
done
1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .