Finding files by creation time of another file - linux

What I need to do is find files by the creation time of another file. For example if i create a file at 9am and later i wanted to find all the files created 1 hour after it or 1 hour before it. How would i do that?
I've tried experimenting with "-newer" whilst using "find" but I think "xargs" is what i need to be using.
Thanks

I know this is ooooold, but since I was looking for the same thing...
Here's a oneliner version, basically using the same approach as above:
Modified at least one hour after:
find . -newermt "$(date -d "$(stat -c %y reference_file) + 1 hour")"
Modified one hour before or more:
find . -not -newermt "$(date -d "$(stat -c %y reference_file) - 1 hour")"
Modified within the timespan from one hour before to one hour after
find . -newermt "$(date -d "$(stat -c %y reference_file) - 1 hour")" -not -newermt "$(date -d "$(stat -c %y reference_file) + 1 hour")"
Replace reference_file with the file of your choice. You can of course also use othe timespans than 1 hour
How it works
stat -c %y reference_file will return the modification time.
date -d "[...] + 1 hour" will manupulate the date string to one hour later.
find . -newermt "[...]" will find files with modification time (m) newer than given time (t)
All this requires GNU find 4.3.3 or greater (for -newerXY) and GNU date (to support -d and the complex date strings)

After looking at this I found a way to do this, although it is not the nicest solution as it requires integer arithmetic to be done on time.
The idea is to take the seconds since Unix epoch (aka Unix time) from your reference file, do some integer arithmetic on this to get your offset time (one hour before, or after in your example). Then you use find with the -newer parameter.
Example code:
# Get the mtime of your reference file in unix time format,
# assumes 'reference_file' is the name of the file you're using as a benchmark
reference_unix_time=$(ls -l --time-style=+%s reference_file | awk '{ print $6 }')
# Offset 1 hour after reference time
let unix_time_after="$reference_unix_time+60*60"
# Convert to date time with GNU date, for future use with find command
date_time=$(date --date #$unix_time_after '+%Y/%m/%d %H:%M:%S')
# Find files (in current directory or below)which are newer than the reference
# time + 1hour
find . -type f -newermt "$date_time"
For your example of file created upto one hour before the reference file you could use
# Offset 1 hour before reference time
let unix_time_before="$reference_unix_time-60*60"
# Convert to date time with GNU date...
date_time=$(date --date #$unix_time_before '+%Y/%m/%d %H:%M:%S')
# Find files (in current directory or below which were generated
# upto 1 hour before the reference file
find . -type f -not -newermt "$date_time"
Note that all the above is based on the last modification time of files.
The above has been tested with GNU Find (4.5.10), GNU Date (8.15) and GNU Bash (4.2.37).

Related

linux script that will delete files from previous month

I am new in linux scripting and I have never created .sh file before.
I need to create a script that will delete all the files which are from previous month.
I have gone through the
find /path/to/files* -mtime +5 -exec rm {} \;
but find useless as days in a month can vary from 30 -31 days.
Please help me on this problem. thanks
Run below commands to delete last month file in working Directory.
1st you can see last moth files in working directory run
sudo find . -mtime +30
Numeric arguments can be specified as
+n for greater than n,
-n for less than n,
n for exactly n.
sudo find . -mtime +30 -delete
to delete all files in the systems you can run as below
sudo find / -mtime +30 -delete
Well, first off - how important is it your purge last month? I mean - if you run your script on May 1st, are you really expecting to delete the files from last night?
For most purposes - find -mtime +30 is sufficient, as it's a rolling 30d window.
However, if you really want to 'last month and older' then you have to get a bit more creative, because Unix works on time stamps - in seconds. 30d in seconds is a fixed window, but as you note - 1 calendar month is not.
It gets worse yet if you bear in mind that 'last month' may well also be 'last year' as well.
So to get exactly one month ago:
perl -MTime::Piece -e 'print localtime -> add_months(-1);'
To turn that into a Unix timestamp:
perl -MTime::Piece -e 'print localtime -> add_months(-1) -> epoch;'
To actually figure out the time stamp of the start of the last month is slightly more complicated though - the easiest way is probably to do the above, and then 'figure out' the time stamp of the first day.
E.g.
perl -MTime::Piece -e 'print localtime->strptime(localtime->add_months(-1)->strftime("%Y%m"),"%Y%m);'
We subtract 1 month from today, reformat it as 'year/month' and then re-parse 'year/month' with no day to get the first day of the month.
Obligatory bash solution. From the working directory containing the files to remove, you could run this
for i in $(ls -al | awk '/May/{print $NF}'); do rm -rf $i; done
It will explicitly match all files create in May and then remove them.
The ls -al command lists out the files with their dates and then the awk command matches the files with a date of May and then prints out only the file name. You can test it out before pulling the trigger by running this
ls -al | awk '/May/{print $NF}'
Once you are certain that the files being found are the ones you want to remove, you can run the for loop to remove them.

Find files in created between a date range

I use AIX via telnet here at work, and I'd like to know how to find files in a specific folder between a date range. For example: I want to find all files in folder X that were created between 01-Aug-13 and 31-Aug-13.
Observations:
The touch trick (where you create two empty files to use the -newer option) does not work for me, once the user roles that I have on the server does not allow me to create files.
I need to find between specific dates, not days (like: files that were created more than 30 days ago, etc...)
If you use GNU find, since version 4.3.3 you can do:
find -newerct "1 Aug 2013" ! -newerct "1 Sep 2013" -ls
It will accept any date string accepted by GNU date -d.
You can change the c in -newerct to any of a, B, c, or m for looking at atime/birth/ctime/mtime.
Another example - list files modified between 17:30 and 22:00 on Nov 6 2017:
find -newermt "2017-11-06 17:30:00" ! -newermt "2017-11-06 22:00:00" -ls
Full details from man find:
-newerXY reference
Compares the timestamp of the current file with reference. The reference argument is normally the name of a file (and one of its timestamps is used
for the comparison) but it may also be a string describing an absolute time. X and Y are placeholders for other letters, and these letters select
which time belonging to how reference is used for the comparison.
a The access time of the file reference
B The birth time of the file reference
c The inode status change time of reference
m The modification time of the file reference
t reference is interpreted directly as a time
Some combinations are invalid; for example, it is invalid for X to be t. Some combinations are not implemented on all systems; for example B is not
supported on all systems. If an invalid or unsupported combination of XY is specified, a fatal error results. Time specifications are interpreted as
for the argument to the -d option of GNU date. If you try to use the birth time of a reference file, and the birth time cannot be determined, a fatal
error message results. If you specify a test which refers to the birth time of files being examined, this test will fail for any files where the
birth time is unknown.
Try the following command:
find /var/tmp -mtime +2 -a -mtime -8 -ls
This will allow you to find files in /var/tmp folder that are older than 2 days but not older than 8 days.
Some good solutions on here. Wanted to share mine as well as it is short and simple.
I'm using find (GNU findutils) 4.5.11
$ find search/path/ -newermt 20130801 \! -newermt 20130831
You can use the below to find what you need.
Find files older than a specific date/time:
find ~/ -mtime $(echo $(date +%s) - $(date +%s -d"Dec 31, 2009 23:59:59") | bc -l | awk '{print $1 / 86400}' | bc -l)
Or you can find files between two dates. First date more recent, last date, older. You can go down to the second, and you don't have to use mtime. You can use whatever you need.
find . -mtime $(date +%s -d"Aug 10, 2013 23:59:59") -mtime $(date +%s -d"Aug 1, 2013 23:59:59")
Use stat to get the creation time. You can compare the time in the format YYYY-MM-DD HH:MM:SS lexicographically.
This work on Linux with modification time, creation time is not supported. On AIX, the -c option might not be supported, but you should be able to get the information anyway, using grep if nothing else works.
#! /bin/bash
from='2013-08-01 00:00:00.0000000000' # 01-Aug-13
to='2013-08-31 23:59:59.9999999999' # 31-Aug-13
for file in * ; do
modified=$( stat -c%y "$file" )
if [[ $from < $modified && $modified < $to ]] ; then
echo "$file"
fi
done
You can use the following commands to list files between 2 specific dates:
Search on current (.) directory:
find . -type f -newermt "2019-01-01" ! -newermt "2019-05-01"
Search on /var/any/directory/ directory:
find /var/any/directory/ -type f -newermt "2019-01-01" ! -newermt "2019-05-01"
Script oldfiles
I've tried to answer this question in a more complete way, and I ended up creating a complete script with options to help you understand the find command.
The script oldfiles is in this repository
To "create" a new find command you run it with the option -n (dry-run), and it will print to you the correct find command you need to use.
Of course, if you omit the -n it will just run, no need to retype the find command.
Usage:
oldfiles [-v...] ([-h|-V|-n] | {[(-a|-u) | (-m|-t) | -c] (-i | -d | -o| -y | -g) N (-\> | -\< | -\=) [-p "pat"]})
Where the options are classified in the following groups:
Help & Info:
-h, --help : Show this help.
-V, --version : Show version.
-v, --verbose : Turn verbose mode on (cumulative).
-n, --dry-run : Do not run, just explain how to create a "find" command
Time type (access/use, modification time or changed status):
-a or -u : access (use) time
-m or -t : modification time (default)
-c : inode status change
Time range (where N is a positive integer):
-i N : minutes (default, with N equal 1 min)
-d N : days
-o N : months
-y N : years
-g N : N is a DATE (example: "2017-07-06 22:17:15")
Tests:
-p "pat" : optional pattern to match (example: -p "*.c" to find c files) (default -p "*")
-\> : file is newer than given range, ie, time modified after it.
-< : file is older than given range, ie, time is from before it. (default)
-= : file that is exactly N (min, day, month, year) old.
Example:
Find C source files newer than 10 minutes (access time) (with verbosity 3):
oldfiles -a -i 10 -p"*.c" -\> -nvvv
Starting oldfiles script, by beco, version 20170706.202054...
oldfiles -vvv -a -i 10 -p "*.c" -\> -n
Looking for "*.c" files with (a)ccess time newer than 10 minute(s)
find . -name "*.c" -type f -amin -10 -exec ls -ltu --time-style=long-iso {} +
Dry-run
Find H header files older than a month (modification time) (verbosity 2):
oldfiles -m -o 1 -p"*.h" -\< -nvv
Starting oldfiles script, by beco, version 20170706.202054...
oldfiles -vv -m -o 1 -p "*.h" -\< -n
find . -name "*.h" -type f -mtime +30 -exec ls -lt --time-style=long-iso {} +
Dry-run
Find all (*) files within a single day (Dec, 1, 2016; no verbosity, dry-run):
oldfiles -mng "2016-12-01" -\=
find . -name "*" -type f -newermt "2016-11-30 23:59:59" ! -newermt "2016-12-01 23:59:59" -exec ls -lt --time-style=long-iso {} +
Of course, removing the -n the program will run the find command itself and save you the trouble.
I hope this helps everyone finally learn this {a,c,t}{time,min} options.
The LS output:
You will also notice that the ls option ls OPT changes to match the type of time you choose.
Link to clone/download of the oldfiles script:
https://github.com/drbeco/oldfiles
Explanation: Use unix command find with -ctime (creation time) flag.
The find utility recursively descends the directory tree for each path listed, evaluating an expression (composed of the 'primaries' and 'operands') in terms of each file in the tree.
Solution: According to official documentation:
-ctime n[smhdw]
If no units are specified, this primary evaluates to true if the difference
between the time of last change of file status information and the time find
was started, rounded up to the next full 24-hour period, is n 24-hour peri-
ods.
If units are specified, this primary evaluates to true if the difference
between the time of last change of file status information and the time find
was started is exactly n units. Please refer to the -atime primary descrip-
tion for information on supported time units.
Formula:
find <path> -ctime +[number][timeMeasurement] -ctime -[number][timeMeasurment]
Examples:
1.Find everything that were created after 1 week ago and before 2 weeks ago.
find / -ctime +1w -ctime -2w
2.Find all javascript files (.js) in current directory that were created between 1 day ago to 3 days ago.
find . -name "*\.js" -type f -ctime +1d -ctime -3d

Find files created 30 minutes before AND after a given file - UNIX

I am trying to figure out the command to display all files created 30 minutes (as an example) before and after another file was created. So far I managed to find files newer than that file
but I cannot work out how to look for both before and after given time.
A command I have used:
find -type f -newer file.txt -cmin -30
This works fine but only does half of what I am trying to do.
Also, I need to modify that to search for setuid files only, which I THINK I can do by adding the -perm -4000 in that command.
Any suggestions?
As far as I know there is no way to find file creation time.
You can try by modification time (this will get all files last-modified between 5th and 8th)
find . -type f -newermt 2012-10-05 ! -newermt 2012-10-08
(or access time replace newermt with newerat)
newerXY is flag to compare timestamps of current file with reference (see man find for more info).
According to man find (on my debian) there are 4 flags (aside from t to interpret directly as time)
a The access time of the file reference
B The birth time of the file reference
c The inode status change time of reference
m The modification time of the file reference
You can also try with 'B' birth time but it does not work for me, gives me error. I don't know why it is included in the man page
compare to another file
find / -newer file
find / ! -newer file
You can create temp file (one with modification time 30 min before the target file, another 30 mins after)
touch -d `stat -c %y test.txt` - 30 temp/before_temp
touch -d `stat -c %y test.txt` + 30 temp/after_temp
find / -newer temp/before_temp ! -newer temp/after_temp
touch -d takes a date option, so if you add and subtract correctly, this should work.

Finding files modified within an hour of another file

If i have 3 files called 1.txt,2.txt and 3.txt for example and they were created an hour apart, say 1pm 2pm and 3pm respectively. What I need is a command that finds all files modified within an hour of a specific file.
I'm in the same directory as the files in the terminal and all files are setuid permission
I've been trying:
find . -type f -perm -4000 -newer 2.txt -mmin -60 -print
This should return 3.txt but it doesn't
What would use to file created in the hour before or after 2.txt?
Try this
touch /tmp/temp -t time1
touch /tmp/ntemp -t time2
find . -newer /tmp/temp -a ! -newer /tmp/ntemp -exec ls -l {} \; 2>/dev/null
where
time1 = time of file creation - 1hr
time2 = time of file creation + 1hr
Ex:
time1 = 201210041500
time2 = 201210041700
Here is my logic -
First get time of last access of file in seconds since Epoch in some variable.
time_in_sec=$(stat -c %X 2.txt)
Get the time of last hour ( ie 3600 seconds back )
one_hr_old_time_in_sec=`expr $time_in_sec - 3600`
Convert it into format suitable for find command
newerthan=$(date -d #$one_hr_old_time_in_sec '+%m-%d-%y%n %H:%M:%S')
Convert time of original file in format suitable for find command
olderthan=$(date -d #$time_in_sec '+%m-%d-%y%n%H:%M:%S')
Get the list of files modified between two time periods using find command
find . -newermt "$newerthan" ! -newermt "$olderthan" -print
If it works you can write a small shell script which will take file name as parameter and can try for +3600 also.
Honestly, I haven't tried it. Hope it works !
The previous solution can be simplified since -newermt shall accept the same formats than 'date' including #N for N seconds since epoch.
Also for the 'stat' command it is probably better to use -Y (the time of last modification) instead of -X (the time of last access).
So the command to find the files modified + or - 1 hours of 2.txt is
N=$(stat -c %Y 2.txt)
find . -newermt #$((N-3600)) ! -newermt #$((N+3600)) -print
If you are running this after 4pm, given your example, it makes sense that it wouldn't return 3.txt, as -newer 2.txt -mmin -60 means "modified in the last 60 minutes, and more recently than 2.txt", not "modified less than 60 minutes after 2.txt". I don't think find currently has options to do what you're wanting (at least, the version I have doesn't), but it shouldn't be too hard to script in python or perl.

Recursively find all files newer than a given time [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 1 year ago.
The community reviewed whether to reopen this question 10 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
Given a time_t:
⚡ date -ur 1312603983
Sat 6 Aug 2011 04:13:03 UTC
I'm looking for a bash one-liner that lists all files newer. The comparison should take the timezone into account.
Something like
find . --newer 1312603983
But with a time_t instead of a file.
You can find every file what is created/modified in the last day, use this example:
find /directory -newermt $(date +%Y-%m-%d -d '1 day ago') -type f -print
for finding everything in the last week, use '1 week ago' or '7 day ago'
anything you want
Maybe someone can use it. Find all files which were modified within a certain time frame recursively, just run:
find . -type f -newermt "2013-06-01" \! -newermt "2013-06-20"
This is a bit circuitous because touch doesn't take a raw time_t value, but it should do the job pretty safely in a script. (The -r option to date is present in MacOS X; I've not double-checked GNU.) The 'time' variable could be avoided by writing the command substitution directly in the touch command line.
time=$(date -r 1312603983 '+%Y%m%d%H%M.%S')
marker=/tmp/marker.$$
trap "rm -f $marker; exit 1" 0 1 2 3 13 15
touch -t $time $marker
find . -type f -newer $marker
rm -f $marker
trap 0
Assuming a modern release, find -newermt is powerful:
find -newermt '10 minutes ago' ## other units work too, see `Date input formats`
or, if you want to specify a time_t (seconds since epoch):
find -newermt #1568670245
For reference, -newermt is not directly listed in the man page for find. Instead, it is shown as -newerXY, where XY are placeholders for mt. Other replacements are legal, but not applicable for this solution.
From man find -newerXY:
Time specifications are interpreted as for the argument to the -d option of GNU date.
So the following are equivalent to the initial example:
find -newermt "$(date '+%Y-%m-%d %H:%M:%S' -d '10 minutes ago')" ## long form using 'date'
find -newermt "#$(date +%s -d '10 minutes ago')" ## short form using 'date' -- notice '#'
The date -d (and find -newermt) arguments are quite flexible, but the documentation is obscure. Here's one source that seems to be on point: Date input formats
Given a unix timestamp (seconds since epoch) of 1494500000, do:
find . -type f -newermt "$(date '+%Y-%m-%d %H:%M:%S' -d #1494500000)"
To grep those files for "foo":
find . -type f -newermt "$(date '+%Y-%m-%d %H:%M:%S' -d #1494500000)" -exec grep -H 'foo' '{}' \;
You can also do this without a marker file.
The %s format to date is seconds since the epoch. find's -mmin flag takes an argument in minutes, so divide the difference in seconds by 60. And the "-" in front of age means find files whose last modification is less than age.
time=1312603983
now=$(date +'%s')
((age = (now - time) / 60))
find . -type f -mmin -$age
With newer versions of gnu find you can use -newermt, which makes it trivial.
There is PowerShell available on Linux for some time so I recommend to use that since it does not deal just with pure text but handles real objects and so avoids formatting and make the task much easier
ls -recurse | where lastwritetime -gt ((get-date).AddDays(-1))
It's another way. You can recursively find files newer than a given timestamp using touch -d and find /dir -newer commands.
For example, if you need find files newer than '1 June 2018 11:02', you can create a file with this creation date.
touch -d '1 June 2018 11:02' ref_timestamp
Then, you can use the file timestamp as reference in find command.
find /dir -newer ref_timestamp
So there's another way (and it is portable to some extent_
(python <<EOF
import fnmatch
import os
import os.path as path
import time
matches = []
def find(dirname=None, newerThan=3*24*3600, olderThan=None):
for root, dirnames, filenames in os.walk(dirname or '.'):
for filename in fnmatch.filter(filenames, '*'):
filepath = os.path.join(root, filename)
matches.append(path)
ts_now = time.time()
newer = ts_now - path.getmtime(filepath) < newerThan
older = ts_now - path.getmtime(filepath) > newerThan
if newerThan and newer or olderThan and older: print filepath
for dirname in dirnames:
if dirname not in ['.', '..']:
print 'dir:', dirname
find(dirname)
find('.')
EOF
) | xargs -I '{}' echo found file modified within 3 days '{}'

Resources