Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I find and delete files based on date in a linux shell script without find?

Tags:

linux

bash

shell

PLEASE NOTE THAT I CANNOT USE 'find' IN THE TARGET ENVIRONMENT

I need to delete all files more than 7 days old in a linux shell script. SOmething like:

FILES=./path/to/dir
for f in $FILES
do
  echo "Processing $f file..."
  # take action on each file. $f store current file name
  # perhaps stat each file to get the last modified date and then delete files with date older than today -7 days.

done

Can I use 'stat' to do this? I was trying to use

find *.gz -mtime +7 -delete

but discovered that I cannot use find on the target system (there is no permission for the cron user and this can't be changed). Target system is Redhat Enterprise.

The file names are formatted like this:

gzip > /mnt/target03/rest-of-path/web/backups/DATABASENAME_date "+%Y-%m-%d".gz

like image 604
codecowboy Avatar asked Dec 21 '11 16:12

codecowboy


2 Answers

This should work:

#!/bin/sh

DIR="/path/to/your/files"
now=$(date +%s)
DAYS=30

for file in "$DIR/"*
do
    if [ $(((`stat $file -c '%Y'`) + (86400 * $DAYS))) -lt $now ]
    then
    # process / rm / whatever the file...
    fi
done

A bit of explanation: stat <file> -c '%Z' gives the modification time of the file as seconds since the UNIX epoch for a file, and $(date +%s) gives the current UNIX timestamp. Then there's just a simple check to see whether the file's timestamp, plus seven days' worth of seconds, is greater than the current timestamp.

like image 187
pgl Avatar answered Sep 22 '22 09:09

pgl


Since you have time in the filename then use that to time the deletion heres some code that does that :

This script gets the current time in seconds since epoch and then calculates the timestamp 7 days ago. Then for each file parses the filename and converts the date embeded in each filename to a timestamp then compares timestamps to determine which files to delete. Using timestamps gets rid of all hassles with working with dates directly (leap year, different days in months, etc )

The actual remove is commented out so you can test the code.

#funciton to get timestamp X days prior to input timestamp
# arg1 = number of days past input timestamp
# arg2 = timestamp ( e.g. 1324505111 ) seconds past epoch
getTimestampDaysInPast () {
    daysinpast=$1
    seconds=$2
    while [ $daysinpast -gt 0 ] ; do
    daysinpast=`expr $daysinpast - 1`
    seconds=`expr $seconds - 86400`
    done
# make midnight
    mod=`expr $seconds % 86400`
    seconds=`expr $seconds - $mod`
    echo $seconds
} 
# get current time in seconds since epoch
getCurrentTime() {
    echo `date +"%s"`
}

# parse format and convert time to timestamp
# e.g. 2011-12-23 -> 1324505111
# arg1 = filename with date string in format %Y-%m-%d
getFileTimestamp () {
    filename=$1
    date=`echo $filename |  sed "s/[^0-9\-]*\([0-9\-]*\).*/\1/g"`
    ts=`date -d $date | date +"%s"`
    echo $ts
}

########################### MAIN ############################
# Expect directory where files are to be deleted to be first 
# arg on commandline. If not provided then use current working
# directory

FILEDIR=`pwd`
if [ $# -gt 0 ] ; then 
    FILEDIR=$1
fi
cd $FILEDIR

now=`getCurrentTime`
mustBeBefore=`getTimestampDaysInPast 7 $now`
SAVEIFS=$IFS
# need this to loop around spaces with filenames
IFS=$(echo -en "\n\b")
# for safety change this glob to something more restrictive
for f in * ; do 
    filetime=`getFileTimestamp $f`
    echo "$filetime lt $mustBeBefore"
    if [ $filetime -lt $mustBeBefore ] ; then
    # uncomment this when you have tested this on your system
    echo "rm -f $f"
    fi
done
# only need this if you are going to be doing something else
IFS=$SAVEIFS
like image 45
Cjolly Avatar answered Sep 19 '22 09:09

Cjolly