Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

crontab question

by maderman (Beadle)
on Jul 24, 2001 at 12:00 UTC ( [id://99258]=perlquestion: print w/replies, xml ) Need Help??

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

Hi all, I have a script which updates a DBI::CSV file at 12 midday every day. When I run the program from the command line, all works as expected, but when run by cron, nothing happens (even when it should). Now my entry in the crontab file is : 0 12 * * * /path/to/script After run by cron, DBI->trace level two shows:
DBI 1.14-nothread dispatch trace level set to 2 <- FETCH= HASH(0x1e5948)0keys ('csv_tables' from cache) at cryodynes l +ine 23 . -- DBI::END -> disconnect_all in DBD::File::dr for DBD::CSV::dr (DBI::dr=HASH( +0x1958a0)~ 0x23c714) <- disconnect_all= undef at DBI.pm line 450. -> DESTROY in DBD::File::db for DBD::CSV::db (DBI::db=HASH(0x23c70 +8)~INNER) <- DESTROY= undef during global destruction. -> DESTROY in DBD::File::dr for DBD::CSV::dr (DBI::dr=HASH(0x23c71 +4)~INNER) <- DESTROY= undef during global destruction.
The code of 'script' is below. Any ideas as to why the script doesn't run via cron would be appreciated. Thanks, Stacy.
#!/usr/local/bin/perl -w use DBI; chdir('/path/to/script') || die "Can't chdir: $!\n"; $rxdb = 'rxdb.dat'; $updb = 'uptime_db'; $recdb = 'receiver_db'; $trace = 'trace.log'; unlink("$trace") if (-e "$trace"); #Connect to receiver_db (CSV format) $dbh = DBI->connect("DBI:CSV:f_dir=/p/smader/cryo"); $dbh->{'RaiseError'} = 1; DBI->trace(2,$trace); $dbh->{'csv_tables'}->{'receiver_db'} = { 'eol' => "\n", 'col_names' => ["INSTALLED", "SERIAL", "UPTIME", "PACKAGE"], }; #Get current time in Epoch seconds $now_time = time; #Get current modify time of rxdb.dat $current_mtime = (stat("$rxdb"))[9]; #In Epoch seconds #Get previous modify time $previous_mtime = qx(cat $updb); #In Epoch seconds chomp($previous_mtime); die "$updb contains non-digit value!\n" if ($previous_mtime !~ m/^\d+/); if ($current_mtime eq $previous_mtime) { #rxdb.dat hasn't been modified in the last #24 hours. Add 24 to values in $recdb. &update(24); exit; } elsif ($previous_mtime < $current_mtime) { #rxdb.dat has been modified. Get number of #hours since last modification and update #$recdb. Put current mtime into $updb. #Backup receiver_db $td_str = &format_date(1); system "cp -f $recdb $recdb.$td_str"; #Get number of hours since rxdb.dat was changed. $hours = ($current_mtime - $previous_mtime) / 3600; &update($hours); #Reset $updb to current mtime of rxdb.dat open(TMP,">$updb") or die "Can't open $updb: $!\n"; print TMP "$current_mtime"; close(TMP); exit; } else { die "$rxdb modification time greater than current time!\n"; exit; } ###################################################### sub update { ($add) = @_; #See which receivers are present AND available open(DB, "$rxdb") or die "Can't open $rxdb: $!"; $i = 0; while (<DB>) { $i++; if (m/^(\$\$package)/) { #Is package present & available? @db = `more $rxdb`; if ($db[$i+14] =~ m/yes/ && $db[$i+15] =~ m/yes/) { $rx_name = (split '=', $db[$i])[1]; $rx_name =~ s/^\s+//; #remove leading whitespace $rx_name =~ s/\s+$//; #remove trailing whitespace if ($rx_name =~ m/^[57]0CM/) { $test = '50/70CM'; } elsif ($rx_name =~ m/^[SCX]\-BAND/) { $test = 'ATPROTO'; } elsif ($rx_name =~ m/^GALILEO/) { $test = 'GALILEO'; } elsif ($rx_name =~ m/^K/) { $test = 'K/Ku'; } elsif ($rx_name =~ m/^METH/) { $test = 'METHANOL'; } elsif ($rx_name =~ m/^MULTI/) { $test = 'MULTI'; } elsif ($rx_name =~ m/^(H-OH)/) { $test = 'H-OH'; } #Get previous uptimes from $recdb, and add to them. open(TMP,"$recdb") or die "Can't open $recdb: $!\n"; while (<TMP>) { chomp; ($uptime,$package) = (split(',',$_))[2,3]; if ($package eq $test) { $new_uptime = $uptime + $add; } } close(TMP); $dbh->do(q{UPDATE receiver_db SET UPTIME = ? WHERE PACKAGE = ? +}, 'undef',$new_uptime,$test); } } } close(DB); return; } ###################################################### sub format_date { my ($input) = @_; ($min,$hour,$mday,$month,$year) = (localtime($now_time))[1..5]; $min = sprintf "%02d", $min; $hour = sprintf "%02d", $hour; $mday = sprintf "%02d", $mday; $month = sprintf "%02d", $month+1; $year += 1900; $time = join('',$hour,$min); $date = join('',$mday,$month,substr($year,-2,2)); $td_str = join('_',$time,$date); if ($input eq '0') { return($min,$hour,$mday,$month,$year); } else { return($td_str); } }

Replies are listed 'Best First'.
Re: crontab question
by Wookie (Beadle) on Jul 24, 2001 at 12:56 UTC
    I have found that most cron vs command line problems are caused by enviroment.

    Assuming you setup most of your enviroment using your .profile in your home dir - then I'd suggest using a small shell wrapper script to run the perl - and enter that into cron.

    The script would read something like:
    #!/bin/ksh # Read in enviroment . /home/user/.profile # Run Perl script exec /path/script -options
    Then simply run this script from crontab.

    Hope this helps :).
    game(Wookie,opponent) eq 'Wookie' ? undef $problem : remove_limbs(arms,opponent);
Re: crontab question
by arhuman (Vicar) on Jul 24, 2001 at 12:31 UTC
    Just my 2 cents Idea :

    Did you check your path ?
    Did your try your script from different directories ?
    You should try it with explicit paths :
    #Is package present & available? @db = `/mybin/more $rxdb`;

    "nothing happens" You didn't get any report by mail ?

    Anyway when I don't know what's going on, I usually put print statement everywhere
    to display the content of the main variables
    (enclosed by visible chars : brace,bang...to see leading/trailing spaces)
    to see if they're defined and comply to what I expect...

    "Only Bad Coders Code Badly In Perl" (OBC2BIP)
Re: crontab question
by Zaxo (Archbishop) on Jul 24, 2001 at 13:37 UTC

    As Wookie says, cron does not set up an environment unless you tell it to. That can be done at the head of the crontab file.

    Obligatory pickiness: use strict;. That would show that all your variables are global. That is not causing problems in your script since all the names are different. Later modifications could give puzzling failures if a generic temp like $i or $time were reused.

    After Compline,
    Zaxo

Re: crontab question
by jepri (Parson) on Jul 24, 2001 at 13:05 UTC
    The cron docs also say that every line must be terminated by a newline character, or they will be silently ignored. So if you added your script to the last line go back and make sure you have an empty line below it, jsut to be sure.

    ____________________
    Jeremy
    I didn't believe in evil until I dated it.

Re: crontab question
by scottstef (Curate) on Jul 24, 2001 at 17:22 UTC
    Try creating an error log for your crontab entry and sending your error messages to it:
    0 23 * * * /my_path/my_script.pl >> /my_path/errordir/script_errors.txt
    Then you can read the error log for any error messages

    "The social dynamics of the net are a direct consequence of the fact that nobody has yet developed a Remote Strangulation Protocol." -- Larry Wall

      doesn't that append STDOUT /my_path/errordir/script_errors.txt?

      I thought to redirect STDERR in "modern" shells you had to do something like .... &2>/errola.txt where &1 is STDOUT &2 is STDERR and &3 is like a temporary redirection handle (just like &4), so that you can swap "streams"

        That would be 2>/errola.txt rather than &2>/errola.txt, the & is used when redirecting one file descriptor to another: 2>&1 redirects stderr to stdout. The easiest way to remember where the & goes is that: &2>1 could either redirect to filedescriptor 1 or to a file named '1' and a file named '1' isn't that unusual a name while 2>&1 is either going to redirect to filedescriptor 1 or a file named '&1' and it's unlikely that someone will want a file named '&1' so that is the way to do it. If you ever want to redirect to a file named '&1' you could: 2>'&1' but I can't think of a situation where you would ever want a file named &1, but then again I can't think of a situation where someone would want an album by N*Sync and I was totally wrong there.

      If you write to stderr the output will be emailed to the user named in the MAILTO environment variable, or to the crontab owner (unless MAILTO is defined as an empty string), but this may vary with implementation. That's probably easier than keeping a separate log file.

Re: crontab question
by maderman (Beadle) on Jul 25, 2001 at 06:17 UTC
    Hi all, well I found out what the problem was. It was with the following:
    @db = `more $rxdb`; if ($db[$i+14] =~ m/yes/ && $db[$i+15] =~ m/yes/) {
    When run from the command line, this worked fine, but when run from cron, $db$i+14 and $db$i+15 were not matching the lines they were supposed to. Once I replaced $i+14 and $i+15 with $i+17 and $i+18 respectively, I got the cron job to do exactly what I wanted. BTW, the job in the crontab was:
    0 12 * * * /path/to/script > /path/to/error/log 2>&1
    So, it looks like cron added three extra rows while performing the @db = `more $rxdb` command. Thanks for all your help and suggestions. Regards, Stacy.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://99258]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (6)
As of 2024-03-29 01:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found