简体   繁体   中英

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

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

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.

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

If you prefer to rely on the date in the filenames, you can use this routine, that checks if a date is older than another:

is_older(){
    local dtcmp=`date -d "$1" +%Y%m%d`; shift
    local today=`date -d "$*" +%Y%m%d`
    return `test $((today - dtcmp)) -gt 0`
}

and then you can loop through filenames, passing '-7 days' as the second date:

for filename in *;
do
    dt_file=`echo $filename | grep -o -E '[12][0-9]{3}(-[0-9]{2}){2}'`
    if is_older "$dt_file" -7 days; then
        # rm $filename or whatever
    fi
done

In is_older routine, date -d "-7 days" +%Y%m%d will return the date of 7 days before, in numeric format ready for the comparison.

DIR=''

now=$(date +%s)

for file in "$DIR/"*
do
echo $(($(stat "$file" -c '%Z') + $((86400 * 7))))
echo "----------"
echo $now

done

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM