blackcode6 has asked for the wisdom of the Perl Monks concerning the following question:

Fellow monks, I wrote a small inefficient perl script that checks to see if the time has changed on the /var/log/httpd/access_log file. If the file time is the same it prints a period. Once the file is "touch"ed by anything and the time changes, the script prints an "x". Eventually, I want to move to a specific response instead of an "x". The file uses 12% of cpu process because of its while loop nature. Is there a better way to do this?
#!/usr/bin/perl print "Testing to see if file changes.\n"; $listing = `ls -al access_log`; @fields = split /" "/,$listing; foreach (@fields) { if (/[0-9][0-9]:[0-9][0-9]/) { $status = $&; print "Status is :",$status,"\n"; } else { print "Didn't find anything.\n"; } } @fields = split /:/, $status; $hours = @fields[0]; $minutes = @fields[1]; print "hours :",$hours,"\n"; print "minutes :",$minutes,"\n"; $hours2 = $hours; $minutes2 = $minutes; @fields = (); while (1) { while ($hours == $hours2 && $minutes == $minutes2) { $listing = `ls -al access_log`; @fields = split /" "/,$listing; foreach (@fields) { if (/[0-9][0-9]:[0-9][0-9]/) { $status = $&; } else { # print "Didn't find anything suckker.\n"; } } @fields = split/:/,$status; $hours = @fields[0]; $minutes=@fields[1]; @fields= (); print "."; # meaning the time is the still the same } $hours2 = $hours; $minutes2 = $minutes; print "x"; # meaning the time has changed; file touched }

Replies are listed 'Best First'.
Re: Perl process to constantly detect the time change of a file?
by Rich36 (Chaplain) on May 03, 2002 at 20:33 UTC

    You could cut out a lot of code by using stat - specifically "mtime", which is the "last modify time in seconds since the epoch". I would suggest putting a small sleep time in the loop as well, just so you're not constantly hitting your machine - unless it's absolutely crucial that you know the second when this file has changed.

    my $file = "somefile.txt"; # Establish a base "last accessed time" my $lastaccessed = (stat($file))[9]; while(1) { if ((stat($file))[9] == $lastaccessed) { # The file is the same } else { # File is different } sleep 5; }

    Check the docs for stat - it provides a lot of useful info about files.


    Rich36
    There's more than one way to screw it up...

      Right -- of course one would usually want to make sure it goes like this (Rich36 assumes this goes without saying):
      while(1) { my $modtime = (stat($file))[9]; if ($modtime == $lastaccessed) { # The file is the same } else { # File is different; do whatever, and also: $lastaccessed = $modtime; } sleep 5; }
Re: Perl process to constantly detect the time change of a file?
by stefp (Vicar) on May 04, 2002 at 02:31 UTC
    May be you want first to check out packages that do similar stuff like File::Tail, File::MultiTail and even POE::Wheel::FollowTail if you want to insert you stuff in an event framework. Even when I don't use a package or don't borrow code from it, I sometimes notice they deal with issues I had overlooked.

    -- stefp -- check out TeXmacs wiki

      I think this is an excellent advice as it looks at the problem from a different perspective. Instead of polling the time the file was last changed, you wait for the file to change. (this of course assumes you can read from the file)

      ++stefp++

      Update: Actually, coming to read the original post again, this will not work if the file is "touched" by another process, only if appended to. Nonetheless, --stefp++ :-)

Re: Perl process to constantly detect the time change on a file?
by bluto (Curate) on May 03, 2002 at 20:30 UTC
    To answer your question, use the sleep function in between each iteration. If you only sleep for a second or two each time through, you will save a boat load of cpu time.

    If you can get away with just checking once per minute, and you are on some unix variant, you can run a script via cron.

    On a broader note: This is a very long winded way of doing this. Instead of forking off a process and parsing the output, you can save a lot more CPU time (not to mention coding headaches) by using the stat function and just checking the mtime field.

    bluto