Find files which are created a certain time after or before a particular file was created
Solution 1
Another complicated option:
- get
test.txt
's modification time (mtime
) - calculate
"before delta" = now + hour - mtime
(assumingmtime
is in the past) - calculate
"after delta" = now - hour - mtime if now - mtime > hour else 0
- run
find -type f -mmin -"before delta" -mmin +"after delta"
It finds all files that are modified less than "before delta" minutes ago and greater than "after delta" minutes ago i.e., +/- hour around test.txt
's modification time.
It might be simpler to understand if you draw now
, mtime
, "before"
, "after"
times on a line.
date
command allows to get now
and mtime
.
As a one-liner:
$ find -type f -newermt "$(date -r $file) -1 hour" -a \
\! -newermt "$(date -r $file) +1 hour"
Solution 2
Try the following shell code:
file=</PATH/TO/FILE>
date=$(perl -le '$s = (stat($ARGV[0]))[9]; print $s;' "$file")
now=$(date +%s)
seconds=$((now - date))
mins=$((seconds / 60))
find . -mmin -$((mins + 60 )) -mmin +$((mins - 60)) -print
Solution 3
You could do:
d=$(TZ=UTC0 date -r test.txt +%Y%m%d%H%M.%S)
or
d=$(TZ=UTC0 find test.txt -prune -printf '%TY%Tm%Td%TH%TM.%.2TS\n'
or
d=$(TZ=UTC0 stat -f %Sm -t %Y%m%d%H%M.%S text.txt)
Depending on whether you've got access to GNU date, GNU find or BSD stat (the idea being that unfortunately, there is (reasonably) no POSIX and reliable way to get the modification time of a file)
And then:
TZ=XXX-1 touch -t "$d" sooner
TZ=XXX+1 touch -t "$d" later
find . -newer sooner ! -newer later
The TZ=XXX<offset>
format is standard and means defining the "XXX" timezone as being this <offset>
to UTC, so the "UTC" or "XXX" in the TZ variables above are arbitrary and irrelevant.
Note that none of find -mmin
, stat
, find -printf
, date +%s
, date -r
(let alone --reference
) are portable or POSIX.
perl
is generally more widely available than any of those, and you can do the whole thing with perl (using File::Find
).
ksh93
or zsh
(more easily) also have the ability to perform the whole task internally.
I said reasonably above, because it is possible to get the modification time of a file (as epoch time), provided its name is not too long and doesn't contain newline characters, POSIXly, but it's a bit convoluted:
{
echo ibase=8
printf '%s\n' test.txt |
pax -x ustar -wd |
dd 2> /dev/null bs=4 skip=34 count=3 |
tr -d '\0'
echo
} | bc
Converting it to a YYYYmmddHHMM.SS format in the UTC timezone POSIXly is also possible but also quite an effort (see http://stchaz.free.fr/wide_strftime.sh as an example)
Related videos on Youtube
omarArroum
Updated on September 18, 2022Comments
-
omarArroum over 1 year
I need a shell script which finds files which are created 1 hour before or 1 hour after a particular file (
test.txt
) was created.If I go with
find -newer
, that means I'd have to create a temporary file, usetouch
to change the time on that 1 hour before the creation time of thetest.txt
file, and then use-newer tempFile
to find the files which are newer than thetempFile
, ultimately finding the files which are created 1 hour before the test.txt file. Then I have to go back through that process to find those an hour or more older than the file I'm interested in. That seems like a lot of extra work to go through to answer a simple question.I also see
find -mmin
, but I worry that it's an extension to POSIXfind
.Any other suggestions?
-
Admin over 11 yearsNo common file system records the creation time of a file. You can use the last time a file was modified, the last time it was accessed, and the last time its meta-data was modified. There is no way to know when a file was created (unless you are using an exotic file system.)
-
Admin over 11 yearsMac OS X records the 'birth time of an inode', which is as good as you're going to get for a 'create time'.
-
Admin over 11 yearsThe options to
find
, even GNUfind
, don't make that an easy query. Your best bet is probably to create two temporary files, touch one of them with the oldest time stamp that you want, touch the other with the newest time stamp that you want, and then use-newer
etc. Not neat and tidy. I have tools that would help me, but they're homebrew and not widely available. -
Admin over 11 yearsProbably using the inode change time is an acceptable approximation for a homework assignment, though (perhaps that's even what the professor mistakenly wants).
-
Admin over 11 yearsif I'm not mistaken your question had
linux
tag on SO before the merge. Is GNU find available in your environment? -
Admin over 11 yearsYes, GNU find is available for me. Currently using Debian GNU 6.0.5. Why? Is there a difference in the various finds?
-
-
jordanm over 11 yearsThe
stat
call is not portable. -
Nils over 11 years
date --reference
does not work? This would avoid thestat
command. -
Gilles Quenot over 11 years
stat
substitued for aperl
one-liner -
Gilles Quenot over 11 years
date --reference FILE '+%s'
works for me on archlinux -
Gilles Quenot over 11 years
date --reference FILE '+%s'
doesn't work on Solaris 11. My script is working well on this platform (bash shell). -
omarArroum over 11 yearsApparently there is a 1 line solution to this problem, not sure if that includes any perl scripting or if it's straight bash shell scripting.
-
omarArroum over 11 yearsI see your solution, but isn't there a more 'elegent' way of doing this? Apparently there is a 1 line solution for this problem...
-
jfs over 11 years@teenOmar: I've added a one-line solution
-
omarArroum over 11 yearsWouldn't I have to use
-o
as opposed to-a
since I'm looking for files created 1 hour before OR 1 hour after the file creation/modification. Also is the one liner to be used in conjunction with anything else? I.e does$file
have to be declared before somehow or can I just do"$(date -r test.txt) -1 hour"
? -
omarArroum over 11 yearsOk, @j-f-sebastian tried the various ways out, however the one liner isn't fool proof. Doesn't seem to work all the time, especially when i break it down into separate chunks i.e. finding the files which are created one hour after
test.txt
. Any ideas? -
jfs over 11 years@teenOmar:
-a
is correct: the command returns files that should be both newer thantest.txt
modification time minus an hour and older thantest.txt
modification time plus an hour i.e., in +/- hour aroundtest.txt
time. You can use justtest.txt
instead of$file
. -
jfs over 11 years@teenOmar: It seems I've misread your question. My answer gives files within one hour of
test.txt
. Your question asks about files outside the time range (the answer could be easily modified just swap+/-
in the conditions). To get files modified one hour aftertest.txt
:find -type f -newermt "$(date -r test.txt) +1 hour"
. -
omarArroum over 11 years@j-f-sebastian: what I'm saying is that currently your code picks up anything that is in the timeframe of being newer than the
test.txt
file by up to 59 minutes, as the! -newermt ...
deals with that. Your code currently only finds the files after thetest.txt
file, but it doesn't find the files which were created within the 1 hour tie frame before it. Do you see what I mean? -
jfs over 11 years@teenOmar: your sentences contradict each over. Does it only finds files newer or older than
test.txt
? Do you look at the modification times or something else? I don't know how to say it more clearly. For example, iffile=test.txt
is last modified at 7pm than the command in the answer should find files modified at 6:01pm, 6:30pm, 7:30pm, 7:59pm (same day) and it should not find files modified at 5:30pm, 5:59pm, 8:01pm, 8:30pm. In particular the command should find the file itself. It works as expected on Ubuntu -
omarArroum over 11 yearsHmmmm I see what you're saying, however in my case if I have the following files: 'testBefore.txt' with the modification time of 6pm and then 'test.txt' at 7pm and lastly 'testAfter.txt' at 8pm, your code will only bring up 'test.txt' and 'testAfter.txt', but not 'testBefore.txt'
-
jfs over 11 years@teenOmar: you might have noticed that I'd not used in my example times that are on the boundaries exactly. Try
testBefore.txt
with6:01pm
,test.txt
with 7pm, andtestAfter.txt
with7:59pm
. You could use-61 minutes
instead of-1 hour
to include the boundary. -
omarArroum over 11 yearsYou're right, your solution works ;) Thanks a lot