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?

  • 2
    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.) Oct 6 '12 at 19:05
  • Mac OS X records the 'birth time of an inode', which is as good as you're going to get for a 'create time'. Oct 6 '12 at 19:25
  • 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. Oct 6 '12 at 19:27
  • 1
    Probably using the inode change time is an acceptable approximation for a homework assignment, though (perhaps that's even what the professor mistakenly wants).
    – tripleee
    Oct 6 '12 at 19:29
  • What tools are available? What you're doing is as simple as it gets with only POSIX tools. Oct 6 '12 at 22:37

Try the following shell code:

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
  • The stat call is not portable.
    – jordanm
    Oct 6 '12 at 19:27
  • date --reference does not work? This would avoid the statcommand.
    – Nils
    Oct 6 '12 at 20:46
  • stat substitued for a perl one-liner Oct 6 '12 at 21:17
  • 1
    date --reference FILE '+%s' works for me on archlinux Oct 6 '12 at 21:18
  • date --reference FILE '+%s' doesn't work on Solaris 11. My script is working well on this platform (bash shell). Oct 7 '12 at 5:24

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"
  • 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...
    – omarArroum
    Oct 7 '12 at 11:54
  • @teenOmar: I've added a one-line solution
    – jfs
    Oct 7 '12 at 14:13
  • 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
    Oct 9 '12 at 10:57
  • 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?
    – omarArroum
    Oct 9 '12 at 15:43
  • @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
    Oct 9 '12 at 16:39

You could do:

d=$(TZ=UTC0 date -r test.txt +%Y%m%d%H%M.%S)


d=$(TZ=UTC0 find test.txt -prune -printf '%TY%Tm%Td%TH%TM.%.2TS\n'


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'
} | 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)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.