如何在程序执行中保持标量值?

时间:2011-07-27 07:14:42

标签: perl

代码示例var_inc1.pl

#!/usr/bin/perl -w
my $x = 0;
$x++;
print "value : ".$x."\n";

输出:

  • 第一次:{​​{1}}

    perl var_inc1.pl
  • 第二次:value : 1

    perl var_inc1.pl

但我希望输出为

  • 首次执行:value : 1

    perl var_inc1.pl
  • 第二次执行:value : 1

    perl var_inc1.pl
  • 第三次执行:value : 2

    perl var_inc1.pl

......依此类推,标量值在每次执行程序时都会增加。

3 个答案:

答案 0 :(得分:8)

一旦Perl程序结束,RAM中的所有内容都会消失。如果要在程序运行之间保留值,则需要某种形式的持久存储。您需要什么样的存储空间取决于您对环境的限制以及您需要什么形式的持久性(不同的用户应该看到相同的值并能够更改它,它应该存在多长时间等)。

在Perl 5中获得持久性的最简单(但不是最好)的方法是使用dbmopen函数来创建/打开与哈希相关联的DBM文件:

#!/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\n";

通常,dbmopen已被tie取代,这是将代码与变量相关联的更通用方法。对上述代码采用更现代的方法是:

#!/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\n";

有时您不希望依赖外部资源,在这种情况下您只需编写自修改脚本:

#!/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\n"; #save the current value

print "$x\n";

__DATA__
1

注意,这仅适用于要运行此脚本的所有用户都具有脚本写入权限的情况。如果允许多个用户运行脚本,则会出现安全问题(因为一个用户可以修改脚本以包含将由其他用户运行的恶意代码)。

当然,您也可以使用关系数据库:

#!/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\n";

$dbh->do("UPDATE counter SET value = ? WHERE name = ?", {}, $x, "x");

$dbh->disconnect;

答案 1 :(得分:5)

问题是要记住程序调用之间的值。

我想到了两种技巧:

  1. 您可以让调用者记住该值并将其作为参数传递给Perl脚本。这就是在Web应用程序中维护状态的方式。如果您有不同的呼叫者调用同一个程序,则每个呼叫者都将维护自己的计数器。

  2. 您可以在永久存储中写入和读取值,例如文件。如果您有多个不同的调用者调用Perl程序,这将调用调用的总数,但是如果可以同时尝试多个调用,则必须注意打开存储以便以只有一次调用可以具有的方式进行写入它同时打开;见例如perlopentut如果您想使用文件。

答案 2 :(得分:0)

您可以查看可以将数据库绑定到变量的DBM::Deep。您可以像使用普通的Perl 标量哈希或数组一样使用它,但它使用平面文件数据库自动存储和检索值。编辑:显然不包括标量。

以下是使用哈希模拟示例的示例。

#!/usr/bin/env perl

use strict;
use warnings;

use DBM::Deep;

my %x;
tie %x, 'DBM::Deep', 'test.db';

$x{'x'}++;
print "value : ". $x{'x'} ."\n";