I want to get the number of days since file last modified date to today's date.
I use this $ ls -l uname.txt | awk '{print $6 , "", $7}' but it gives me the last modified date. I want to know the number of days from a last modified date to today's date.
Any way to do this?
Instead of using ls, you can use date -r to tell you the modification date of the file. In addition to that, date's %s specifier, which formats the date in seconds since the epoch, is useful for calculations. Combining the two easily results in the desired number of days:
mod=$(date -r uname.txt +%s)
now=$(date +%s)
days=$(expr \( $now - $mod \) / 86400)
echo $days
Try creating a script:
#!/bin/bash
ftime=`stat -c %Y uname.txt`
ctime=`date +%s`
diff=$(( (ctime - ftime) / 86400 ))
echo $diff
You could wrap up the differences of GNU and BSD stat with some BASH math and basic readable API:
since_last_modified() {
local modified
local now=$(date +%s)
local period=$2
stat -f %m $1 > /dev/null 2>&1 && modified=$(stat -f %m $1) # BSD stat
stat -c %Y $1 > /dev/null 2>&1 && modified=$(stat -c %Y $1) # GNU stat
case $period in
day|days) period=86400 ;; # 1 day in seconds
hour|hours) period=1440 ;; # 1 hour in seconds
minute|minutes) period=60 ;; # 1 minute in seconds
*) period= ;; # default to seconds
esac
if [[ $period > 0 ]]; then
echo "$(( (now - modified) / period ))"
else
echo "$(( now - modified ))"
fi
}
Basic usage of seconds since last modification:
since_last_modified uname.txt
or minutes saved to a variable
minutes_since=$(since_last_modified uname.txt minutes)
Related
Could anyone help me with a UNIX script that extracts the date from the last line of a file, compares it to current date, and if date from file is with 1 hour delay between current date, echo YES?
File.txt
18:48:43 iLIKEtoMOVEitMoveIT
18:58:43 iLIKEtoMOVEitMoveIT
19:22:43 iLIKEtoMOVEitMoveIT
clear line
So far I figured out how to get the last line which has the time:
tail -n 2 File.txt | head c-8
Output = 19:22:43
And how to store the current date as only time in a variable:
TheCurrentDate="date +"%T""
How to compare those 2 HH:MM:SS and calculate if one hour has passed between them, then echo"YES". All put in script.sh
DATE=$(tail -n 2 File.txt | cut -c 1-8 | head -n 1)
FROM_FILE=$(date -d "$DATE" +%s)
NOW=$(date +%s)
DIFFERENCE=$((NOW - FROM_FILE))
if [ $DIFFERENCE -le 3600 ]; then
echo YES
fi
The idea is to convert the timestamp to seconds since epoch (+%s) using date. Then you just compare numbers.
EDIT
Your File.txt should does seem like a log file, where the logging program doesn't bother to prepend the date. As #Jonathan Leffler pointed out, NOW could be 00:15 and FROM_FILE could be 23:45.
In this case, date would interpret FROM_FILE as being the end of today, rather than the end of yesterday. This can be fixed ad-hoc:
DATE=$(tail -n 2 File.txt | cut -c 1-8 | head -n 1)
FROM_FILE=$(date -d "$DATE" +%s)
NOW=$(date +%s)
if [ $FROM_FILE -gt $NOW ]; then
# it's not really in the future, it's from yesterday
FROM_FILE=$((FROM_FILE - 24 * 3600))
fi
DIFFERENCE=$((NOW - FROM_FILE))
if [ $DIFFERENCE -le 3600 ]; then
echo YES
fi
I want to get the time since the last update of a file in a human readable format. On the Internet I found:
now=$(date +%s) # to get timestamp of now
last=$(stat -c %Y /var/cache/apt/) # to get the timestamp of the last update
But now I want to divide now with last and print it in a human readable format in Debian shell?
You can write a function:
time_since() {
file=$1
now=$(date +%s)
file_time=$(stat -c %Y "$file")
seconds=$((now - file_time))
hh=$(( $seconds / 3600 ))
mm=$(( ($seconds - $hh * 3600) / 60 ))
ss=$(( $seconds - $hh * 3600 - $mm * 60 ))
printf '%d:%02d:%02d\n' $hh $mm $ss
}
time_since /var/cache/apt
# output => 332:17:07
Using the bash & printf:
time_since() {
eval "$(stat -s "$1")" # st_mtime=1490029104
TZ=UTC printf "%(%T)T\n" $(( $(printf "%(%s)T") - st_mtime ))
}
time_since file.txt
#out -> 02:07:02
Some duration value (time difference in seconds) is the same as the epoch time. (e.g. the difference in seconds from the epoch (UTC))
How do I find the seconds to the next hour using date? I know I can do
date -d "next hour"
but that just adds 1 hour to the present time. I want it to show the seconds to the next full hour. For example if the current time is 9:39am I want to find the number of seconds to 10am
The epoch timestamp of right now is
now=$(date '+%s')
That of the next hour is
next=$(date -d $(date -d 'next hour' '+%H:00:00') '+%s')
The number of seconds until the next hour is
echo $(( next - now ))
For a continuous solution, use functions:
now() { date +%s; }
next() { date -d $(date -d "next ${1- hour}" '+%H:00:00') '+%s'; }
And now you have
echo $(( $(next) - $(now) ))
and even
echo $(( $(next day) - $(now) ))
Another way
Another slightly mathier approach still uses the epoch timestamp. We know it started on an hour, so the timestamp mod 3600 only equals zero on the hour. Thus
$(( $(date +%s) % 3600 ))
is the number of seconds since the last hour, and
$(( 3600 - $(date +%s) % 3600 ))
is the number of seconds until the next.
Well, there's always the straightforward mathy way:
read min sec <<<$(date +'%M %S')
echo $(( 3600 - 10#$min*60 - 10#$sec ))
EDIT: removed race condition, added explicit radix. Thanks, #rici and #gniourf_gniourf.
With Bash≥4.2 you can use printf with the %(...)T modifier to access dates (current date corresponds to argument -1, or empty since version 4.3):
printf -v left '%(3600-60*10#%M-10#%S)T' -1
echo "$((left))"
Pure Bash and no subshells!
The 10# is here to ensure that Bash's arithmetic (expanded in the $((...))) treats the following number in radix 10. Without this, you'd get an error if the minute or second is 08 or 09.
Try doing this :
LANG=C
now=$(date +%s)
next="$(date |
perl -pe 's/(\d{2}):\d{2}:\d{2}/sprintf "%.2d:00:00", $1 + 1/e')"
next=$(date -d "$next" +%s)
echo $(( next - now ))
OUTPUT :
2422
#!/usr/bin/env bash
is=`date +%S`
im=`date +%M`
echo $((((60-$im)*60)+(60-$is)))
I am new to bash scripts and trying to work an if statement out.
I want to do a check to see if the date stamp of a file is + or - 5 minutes from the time now. I have so far:
#!/bin/bash
MODDATE=$(stat -c '%y' test.txt)
echo moddate= $MODDATE
MODDATE=$(echo $MODDATE |head --bytes=+16)
echo now = $MODDATE
currentdate2=$(date -d "+5 minutes" '+%Y-%m-%d %H:%M')
currentdate3=$(date -d "-5 minutes" '+%Y-%m-%d %H:%M')
echo currentdate2 = $currentdate2
echo currentdate3 = $currentdate3
So this gives me the datestamp of the file (MODDATE) and the date now + or - 5 minutes.
How can i do an IF statement to say "if $MODDATE is between $currentdate2 (+5 minutes from now) and $currentdate3 (-5 minutes from now)" then echo [1] > output.txt ELSE echo [0] > output.txt .
Thank you for all of your help in advance
I recommend you to use date %s to have the date in seconds since 1/1/1970 and make date comparison much easier.
currentdate2=$(date -d "+5 minutes" '+%s')
currentdate3=$(date -d "-5 minutes" '+%s')
Hence,
if [ $moddate -ge $currentdate2 ] && [ $moddate -le $currentdate3 ]; then
....
fi
should make it.
Or even shorter:
[ $moddate -ge $currentdate2 ] && [ $moddate -le $currentdate3 ] && echo "in interval!"
How about you don't try to parse the output of stat and directly take its output in seconds since Epoch with %Y? It would then be easier to use Bash's arithmetic.
Your script would look like this (with proper quoting, modern Bash constructs and lowercase variable names):
#!/bin/bash
moddate=$(stat -c '%Y' test.txt)
echo "moddate=$moddate"
now=$(date +%s)
if ((moddate<=now+5*60)) && ((moddate>=now-5*60)); then
echo "[1]" > output.txt
else
echo "[0]" > output.txt
fi
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