Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question
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.) –  William Pursell 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'. –  Jonathan Leffler 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. –  Jonathan Leffler 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. –  Gilles Oct 6 '12 at 22:37
show 2 more comments

3 Answers 3

up vote 3 down vote accepted

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"
share|improve this answer
    
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... –  teenOmar Oct 7 '12 at 11:54
    
@teenOmar: I've added a one-line solution –  J.F. Sebastian 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" ? –  teenOmar 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? –  teenOmar 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. –  J.F. Sebastian Oct 9 '12 at 16:39
show 6 more comments

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
share|improve this answer
    
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 –  sputnick Oct 6 '12 at 21:17
1  
date --reference FILE '+%s' works for me on archlinux –  sputnick 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). –  sputnick Oct 7 '12 at 5:24
show 1 more comment

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|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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