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

I'm a newbie to perl, and I'm trying to create a script to backup a mysql database every hour from 6:00 AM to 24:00, the script would run from crontab hourly. My worst enemy is the two paragraphs where I try to unlink files from the daily dir that are older than 31 days, and from the weekly that are older than 365.

Also Usually I can't transform my scripts to use strict... :(

What the script does alright (without the last two unlink part) is that it will do only one mysql dump in one hour no matter how many times do you start it, if its the first day in the week and ran in the 6:00 - 6:59 time period the backup will be put in the ./backup/weekly dir, if it's not monday but in the same period it will be created in the ./backup/daily dir. Every other case the dump will placed in ./backup/

I also would like to clean out files from ./backup/daily after 31 days , ./backup/weekly after 365days and from ./backup/ that are older than one day. But this is not working...

My error message (apparently I can't use Dirhandles as well): If the dump file does not exist for this hour(I get most of it because perl warns me about the vars, but I don't get why do I receive the error about "if (-e file)":

~/perl/sandbox]$ ./newtime.pl Name "main::backup_weekly_subdir" used only once: possible typo at ./n +ewtime.pl line 8. Name "main::isdst" used only once: possible typo at ./newtime.pl line +17. Name "main::backup_daily_subdir" used only once: possible typo at ./ne +wtime.pl line 7. Name "main::yday" used only once: possible typo at ./newtime.pl line 1 +7. Use of uninitialized value in -e at ./newtime.pl line 36. Use of uninitialized value $age in numeric gt (>) at ./newtime.pl line + 53. readdir() attempted on invalid dirhandle DH at ./newtime.pl line 60.</ +p>

My error message: If the file does exist for this hour:

Name "main::backup_weekly_subdir" used only once: possible typo at ./n +ewtime.pl line 8. Name "main::isdst" used only once: possible typo at ./newtime.pl line +16. Name "main::backup_daily_subdir" used only once: possible typo at ./ne +wtime.pl line 7. Name "main::yday" used only once: possible typo at ./newtime.pl line 1 +6. The file for this hour already exists! Use of uninitialized value $age in numeric gt (>) at ./newtime.pl line + 52. readdir() attempted on invalid dirhandle DH at ./newtime.pl line 59.

What am I missing? :|

#!/usr/local/bin/perl use warnings; $backup_user = "backupuser"; $backup_password = "backuppassword"; $backup_subdir = "./backup"; $backup_daily_subdir = './'."$backup_subdir".'/daily'; $backup_weekly_subdir = './'."$backup_subdir".'/weekly'; $unique_filename = "$backup_subdir".'/account_backup_' . get_timestamp +().'.sql'; $unique_daily_filename = "$backup_subdir".'/daily/account_backup_' . g +et_timestamp().'.sql'; $unique_weekly_filename = "$backup_subdir".'/weekly/account_backup_' . + get_timestamp().'.sql'; sub get_timestamp { ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(t +ime); $mon += 1; if ($mon < 10) { $mon = "0$mon"; } if ($hour < 10) { $hour = "0$hour"; } if ($min < 10) { $min = "0$min"; } if ($sec < 10) { $sec = "0$sec"; } $year=$year+1900; return $year . '_' . $mon . '_' . $mday . '-' . $hour . '_' . $min +. '_' . $sec; } if (($hour > 5)||($hour < 24)){ my $oldfile = "./backup/account_backup\_$year\_$mon\_".($mday - 1) +."\-$hour\_*"; my $testfile = "./backup/account_backup\_$year\_$mon\_$mday\-$hour +\_*"; if (($hour == 06)&&($wday == 1)){ system("mysqldump --user=$backup_user --add-drop-table --databases a +ccount --password=$backup_password > $unique_daily_filename"); } elsif ($hour == 06){ system("mysqldump --user=$backup_user --add-drop-table --databases a +ccount --password=$backup_password > $unique_weekly_filename"); } if (-e glob($testfile)){ print "The file for this hour already exists!\n"; } else { system("mysqldump --user=$backup_user --add-drop-table --databases a +ccount --password=$backup_password > $unique_filename"); } } else { print "It's not configured to create a backup at this hour!\n"; } #### #### Check for expired backups #### opendir (DH, "./backup/daily"); foreach (readdir(DH)) { next if (/^\./); $age = -M ; if ($age > 31) { push(@daily_goners, $_); } } unlink(@daily_goners); opendir (DH,"./backup/weekly"); foreach (readdir(DH)) { next if (/^\./); $age = -M ; if ($age > 365) { push(@weekly_goners, $_); } } unlink(@weekly_goners);

My updated code:

#!/usr/local/bin/perl use warnings; $backup_user = "backupuser"; $backup_password = "backuppassword"; $backup_subdir = "./backup"; $backup_daily_subdir = "$backup_subdir".'/daily'; $backup_weekly_subdir = "$backup_subdir".'/weekly'; $unique_filename = "$backup_subdir".'/account_backup_' . get_timestamp +().'.sql'; $unique_daily_filename = "$backup_subdir".'/daily/account_backup_' . g +et_timestamp().'.sql'; $unique_weekly_filename = "$backup_subdir".'/weekly/account_backup_' . + get_timestamp().'.sql'; sub get_timestamp { ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(t +ime); $mon += 1; if ($mon < 10) { $mon = "0$mon"; } if ($hour < 10) { $hour = "0$hour"; } if ($min < 10) { $min = "0$min"; } if ($sec < 10) { $sec = "0$sec"; } $year=$year+1900; return $year . '_' . $mon . '_' . $mday . '-' . $hour . '_' . $min +. '_' . $sec; } if (($hour > 5)||($hour < 20)){ my $oldfile = "./backup/account_backup\_$year\_$mon\_".($mday - 1) +."\-$hour\_*"; my $testfile = "./backup/account_backup\_$year\_$mon\_$mday\-$hour +\_*"; if (($hour == 06)&&($wday == 1)){ system("mysqldump --user=$backup_user --add-drop-table --databases a +ccount --password=$backup_password > $unique_daily_filename"); } elsif ($hour == 06){ system("mysqldump --user=$backup_user --add-drop-table --databases a +ccount --password=$backup_password > $unique_weekly_filename"); } if (glob($testfile)){ print "The file for this hour already exists!\n"; } else { system("mysqldump --user=$backup_user --add-drop-table --databases a +ccount --password=$backup_password > $unique_filename"); } } else { print "It's not configured to create a backup at this hour!\n"; } #### #### Check for expired backups #### die unless opendir DIR, "$backup_daily_subdir"; foreach $file (grep {-f && (31 < -M)} readdir DIR) { unlink $file; } closedir DIR; die unless opendir DR, "$backup_weekly_subdir"; foreach $files (grep {-f && (365 < -M)} readdir DR) { unlink $files; } closedir DR;

Replies are listed 'Best First'.
Re: Need help with mysql dump script
by ww (Archbishop) on Aug 17, 2011 at 21:09 UTC
    "Usually I can't transform my scripts to use strict... :( "
    That's a highly suspect statement on several grounds:
    1. It might mean that you think you refine a script to satisfy strict after you have it working...
      or
    2. ... it might mean you can't understand the error messages you get when you add use strict...
      or
    3. ... you mean something else, equally untoward, that I 'just don't get.

    If any of those cases obtain, you need to know
    re 1: that's backwards; strict during writing/testing will save you problems AFTER you think you have everything working.
    re 2: You really need to review the errors and the docs relating to each, until you do understand why your code produces unexpected outcomes.
    re 3: We need clarification.

    And, by the way, your initial inclination to mark the error message with <code.../code> tags was correct.

Re: Need help with mysql dump script
by jethro (Monsignor) on Aug 17, 2011 at 21:24 UTC

    use strict may be inconvenient in the beginning, but you will save a lot of time chasing after silly mistakes. If you get error messages because of that, read the error messages, try to understand them (IMHO the biggest mistake beginners do is to look at error and warning messages as problems instead of as helpful information). If you still don't understand, simply google for the error message, you will get lots of explanations.

    The first warning message you get says it all. You used these variables only once and perl is wondering if you need them at all. Note that you use a string constant in the line "opendir (DH,"./backup/weekly");" even though you have the same value already in $backup_weekly_subdir.

    UPDATED You get an error for "if (-e glob($testfile)){" because glob returns undef in a scalar context if the file doesn't exist. But perl obviously doesn't like "-e undef". Practically you are trying to test for the file existence twice, once with the glob and then with the "-e". Instead you just could check if glob returns undef or not

    Functions like open and opendir return 0 aka false when the opening of the file or dir fails. You always should test for failure:

    opendir (DH,$backup_weekly_subdir) or die "Can't open dir $backup_week +ly_subdir: $!\n";

    Probably there is no dir backup/weekly in your current working directory, i.e. in the directory where your shell was when you started the script. Maybe an absolute path (or a relative path relative to your homedir) is better suited to this

Re: Need help with mysql dump script
by repcsi (Initiate) on Aug 17, 2011 at 22:58 UTC

    Now I updated my code and it works! :) Thanks! I found another way to delete files that are older than x days, however, something strange came up... I don't know why it happened, but if I use the second delete section like this:

    #### #### Check for expired backups #### print $backup_daily_subdir."\n"; die unless chdir "$backup_daily_subdir"; die unless opendir DIR, "."; foreach $file (grep {-f && (31 < -M)} readdir DIR) { unlink $file; } closedir DIR; print $backup_weekly_subdir."\n"; die unless chdir "$backup_weekly_subdir"; die unless opendir DR, "."; foreach $files (grep {-f && (365 < -M)} readdir DR) { unlink $files; } closedir DR;

    I get this error:

    ~/perl/sandbox]$ ./newtime.pl Name "main::files" used only once: possible typo at ./newtime.pl line +59. Name "main::isdst" used only once: possible typo at ./newtime.pl line +16. Name "main::yday" used only once: possible typo at ./newtime.pl line 1 +6. The file for this hour already exists! Died at ./newtime.pl line 57.

    Line 57 is -> die unless chdir "$backup_weekly_subdir";

    I got rid of the chdir part to make it work and used only opendir, but why was this happening with chdir(i mean the die on line 57)? "./backup/weekly" was missing so you were right jethro, but I created it, and it was there, I even printed the variables and tried an ls command on it and it was working... I'm clueless, is this safe what I'm doing, or I can wipe something out that I don't want?

        Hello, thanks, but I don't figure it out from this one:
        $ perldoc -f chdir chdir EXPR chdir FILEHANDLE chdir DIRHANDLE chdir Changes the working directory to EXPR, if possible. If +EXPR is omitted, changes to the directory specified by $ENV{HOM +E}, if set; if not, changes to the directory specified by $ENV{LOGDIR}. (Under VMS, the variable $ENV{SYS$LOGIN} +is also checked, and used if it is set.) If neither is set, "ch +dir" does nothing. It returns true on success, false otherwi +se. See the example under "die". On systems that support fchdir(2), you may pass a fileh +andle or directory handle as argument. On systems that don't su +pport fchdir(2), passing handles raises an exception. $

        Also modifing that line, is not working, also I figured, that the file removal is not working, only I just don't get any error messages:(.