Once a Perl program ends, everything in RAM goes away. If you want a value to be retained between runs of a program you need some form of persistant storage. What sort of storage you need depends on what you the constraints of you environment and what form of persistance you need (should different users see the same value and be able to change it, how long should it live, etc.).
The simplest (but not the best) way to get persistence in Perl 5 is to use the dbmopen
function to create/open a DBM file associated with a hash:
#!/usr/bin/perl
use strict;
use warnings;
dbmopen my %storage, "/tmp/foo.db", 0666 #anyone can write to it
or die "could not open /tmp/foo.db: $!";
my $x = ++$storage{x};
print "$x
";
In general, dbmopen
has been replaced by tie
, which is a more general way of associating code with variables. A more modern approach to the code above would be:
#!/usr/bin/perl
use strict;
use warnings;
use DB_File;
tie my %storage, "DB_File", "/tmp/bar.db"
or die "could not open /tmp/bar.db: $!";
my $x = ++$storage{x};
print "$x
";
Sometimes you don't want to be dependent on an external resource, in those cases you can just write a self modifying script:
#!/usr/bin/perl
use strict;
use warnings;
my $pos = tell DATA;
my $x = <DATA>;
$x++;
open DATA, "+<", $0
or die "could not open $0 in read/write mode: $!";
seek DATA, $pos, 0
or die "could not seek to $pos in $0";
print DATA "$x
"; #save the current value
print "$x
";
__DATA__
1
Note, this only works if all the users who are going to run this script have write permission to the script. This is a security issue if more than one user is allowed to run the script (because one user could modify the script to include malicious code which would be run by the other users).
Of course, you could also use a relational database:
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
my $db = "/tmp/baz.db";
my $dbh = DBI->connect(
"dbi:SQLite:dbname=$db",
"", # SQLite doesn't do auth, so make sure the file
"", # permissions are what you need them to be
{
AutoCommit => 1,
PrintError => 0,
RaiseError => 1,
ChopBlanks => 1,
FetchHashKeyName => "NAME_lc",
}
) or die "could not connect to $db: ", DBI->errstr;
my $count = $dbh->selectcol_arrayref("
SELECT count(*)
FROM sqlite_master
WHERE type='table'
AND name='counter';
")->[0];
unless ($count) {
$dbh->do("
CREATE TABLE counter (
name char(50),
value int
);
");
$dbh->do("INSERT INTO counter (name, value) VALUES ('x', 0)");
}
my $x = $dbh->selectcol_arrayref("
SELECT value
FROM counter
WHERE name = 'x'
")->[0];
$x++;
print "$x
";
$dbh->do("UPDATE counter SET value = ? WHERE name = ?", {}, $x, "x");
$dbh->disconnect;