6

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?

7
  • 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, 2012 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, 2012 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, 2012 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, 2012 at 19:29
  • What tools are available? What you're doing is as simple as it gets with only POSIX tools. Oct 6, 2012 at 22:37

3 Answers 3

5

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
6
  • The stat call is not portable.
    – jordanm
    Oct 6, 2012 at 19:27
  • date --reference does not work? This would avoid the statcommand.
    – Nils
    Oct 6, 2012 at 20:46
  • stat substitued for a perl one-liner Oct 6, 2012 at 21:17
  • 1
    date --reference FILE '+%s' works for me on archlinux Oct 6, 2012 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, 2012 at 5:24
4

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"
11
  • 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, 2012 at 11:54
  • @teenOmar: I've added a one-line solution
    – jfs
    Oct 7, 2012 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, 2012 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, 2012 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, 2012 at 16:39
1

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)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .