http://qs1969.pair.com?node_id=66813

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

I am trying to write a primitive counter script. In order to keep the variable accurate i need to save the script over the previous one. how do i do this?

Replies are listed 'Best First'.
Re: How do you save a perl script?
by epoptai (Curate) on Mar 24, 2001 at 07:29 UTC
    It's a bad idea to save the count in the script, but it can be done. I wrote a CGI script to do this while exploring some other confusion.

    Here are two console scripts. The first does the wrong thing by saving the count in itself. The second does the right thing by using an external data file.

    As always in Perl, there are many other ways to increment a count. Neither of these two examples is the worst or best way to do it, they're merely bad and better.

    WRONG

    #!perl -w # self-contained counter script increments and prints value in DATA # set permissions to allow script to read and write itself - epoptai use strict; my$e = 0; my$d; while(<DATA>){$d .= $_} # read data $d++; # increment open (ME,"+>> $0") or die "$!"; # open self unless($^O=~/mswin/i){ flock(ME,2) or die "$!"} # lock unless win32 my@me = <ME>; # read self into array for(@me){ if($_=~m|_\_DATA_\_|){ $e = 1; next } # find last line if($e == 1){ $_ =~ s/\d+/$d/o } # and replace with incremented val +ue } seek ME, 0, 0; # goto top of self truncate ME, 0; # and clear it print ME @me; # write modified contents close ME or die "$!"; print $d; # print incremented value __DATA__ 0

    RIGHT

    #!perl -w # counter script increments and prints value in $file # set permissions to allow script to read and write $file - epoptai use strict; my$file = 'count.txt'; open (FILE,"+>> $file") or die "$!"; # open file unless($^O=~/mswin/i){ flock(FILE,2) or die "$!"} # lock unless win32 local $/ = undef; my$num = <FILE>; # read file into array $num++; seek FILE, 0, 0; # goto top of file truncate FILE, 0; # and clear it print FILE $num; # write modified contents close FILE or die "$!"; print $num; # print incremented value
Re: How do you save a perl script?
by Adam (Vicar) on Mar 24, 2001 at 07:20 UTC
    Don't.
    Instead, save the variable to a separate state file using Data::Dumper, then eval it back into your program. This is rather common, actually. I wrote a package once to create an OO persistent symbol table, I don't have it handy, but here is some basic (non-OO and un-tested) code to start from:
    use strict; my $persistentVar = $defaultvalue; if( -e $persistentStateFile ) { open FH, $persistentStateFile or die "Failed to open '$persistentStateFile': $!"; local $/, $@; my $ps = <FH>; eval $ps; die $@ if $@; } END{ open FH, "> $persistentStateFile" or warn "Failed to open '$persistentStateFile': $!" and exit(1); print FH Data::Dumper->Dump( [$refToPersistentVar], ['nameofpersiste +ntvar'] ) or warn "Failed to print persistent data, $!" and exit(1); close FH or warn "Failed to close $persistentStateFile, $!" and exit(1); }
    However, if you really wanted to replace the currently running script on exit, then do something like:
    END { open FH, "< $0" or warn "Failed to preserve state... couldn't open + '$0', $!" and exit(1); local $/; $_ = <FH>; s/my \$var=$oldvalue/my \$var=$var/m; open FH, "> $0" or warn "Failed to preserve state... couldn't writ +e to '$0', $!" and exit(1); print FH $_; close $file; }
    I don't know if that would work, I wouldn't even try. But if you want, go for it.
      Says Adam:
      Don't. Instead, save the variable to a separate state file using Data::Dumper, then eval it back into your program.
      Holy cow. Dude, it's a counter file. It's just a number. What for you have to use Data::Dumper?

      Wowsers, talk about using a sledge hammer to squish a mosquito!

        Yup. But I'm not interested in the "How do I save a counter" problem. I'm interested in the more generic "How do I save state" problem. I s'pose I should have specified that. Sorry.