Find files which are created a certain time after or before a particular file was created

22,515

Solution 1

Another complicated option:

  1. get test.txt's modification time (mtime)
  2. calculate "before delta" = now + hour - mtime (assuming mtime is in the past)
  3. calculate "after delta" = now - hour - mtime if now - mtime > hour else 0
  4. 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)

Share:
22,515

Related videos on Youtube

omarArroum
Author by

omarArroum

Updated on September 18, 2022

Comments

  • omarArroum
    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, use touch to change the time on that 1 hour before the creation time of the test.txt file, and then use -newer tempFile to find the files which are newer than the tempFile, 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 POSIX find.

    Any other suggestions?

    • Admin
      Admin over 11 years
      No 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
      Admin over 11 years
      Mac OS X records the 'birth time of an inode', which is as good as you're going to get for a 'create time'.
    • Admin
      Admin over 11 years
      The options to find, even GNU find, 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
      Admin over 11 years
      Probably using the inode change time is an acceptable approximation for a homework assignment, though (perhaps that's even what the professor mistakenly wants).
    • Admin
      Admin over 11 years
      if I'm not mistaken your question had linux tag on SO before the merge. Is GNU find available in your environment?
    • Admin
      Admin over 11 years
      Yes, GNU find is available for me. Currently using Debian GNU 6.0.5. Why? Is there a difference in the various finds?
  • jordanm
    jordanm over 11 years
    The stat call is not portable.
  • Nils
    Nils over 11 years
    date --reference does not work? This would avoid the statcommand.
  • Gilles Quenot
    Gilles Quenot over 11 years
    stat substitued for a perl one-liner
  • Gilles Quenot
    Gilles Quenot over 11 years
    date --reference FILE '+%s' works for me on archlinux
  • Gilles Quenot
    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
    omarArroum over 11 years
    Apparently 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
    omarArroum over 11 years
    I 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
    jfs over 11 years
    @teenOmar: I've added a one-line solution
  • omarArroum
    omarArroum over 11 years
    Wouldn'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
    omarArroum over 11 years
    Ok, @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
    jfs over 11 years
    @teenOmar: -a is correct: the command returns files that should be both newer than test.txt modification time minus an hour and older than test.txt modification time plus an hour i.e., in +/- hour around test.txt time. You can use just test.txt instead of $file.
  • jfs
    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 after test.txt: find -type f -newermt "$(date -r test.txt) +1 hour".
  • omarArroum
    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 the test.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
    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, if file=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
    omarArroum over 11 years
    Hmmmm 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
    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 with 6:01pm, test.txt with 7pm, and testAfter.txt with 7:59pm. You could use -61 minutes instead of -1 hour to include the boundary.
  • omarArroum
    omarArroum over 11 years
    You're right, your solution works ;) Thanks a lot