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

Basically I need to do the same type of thing to several scalars with only a slight variation. Is there a simple way to use the value of one scalar to reference another? My googling has come up empty...

This code will hopefully help demonstrate what I mean.

my @message_type=('error','alert','warning'); my ($error,$alert,$warning); my $messages_log='/var/log/messages'; foreach (@message_type) { $($_)=`cat $messages_log |grep $_ | wc -l`; chomp($($_)); $($_)=~s/ //g; }

jcpunk
all code is tested, and doesn't work so there :p (varient on common PM sig for my own ammusment)

Replies are listed 'Best First'.
Re: Not exactly Dereferencing... but in that ball park
by gaal (Parson) on Nov 19, 2005 at 15:15 UTC
    Looks like you need hash subscripting instead of the symbolic referencing you're gesturing at.

    my @message_type=('error','alert','warning'); my %messages; my $messages_log='/var/log/messages'; foreach (@message_type) { $messages{$_}=`cat $messages_log |grep $_ | wc -l`; chomp($messages{$_}); $messages{$_}=~s/ //g; }
      And then turn it into a Perl script instead of a shell script written in Perl.
      my @message_type=('error','alert','warning'); my %messages; my $messages_log='/var/log/messages'; open LOG, $messages_log or die "$!: $messages_log\n"; while (<LOG>) { foreach my $msg_type (@message_type) { ++$messages{$_} if /\Q$msg_type/; } } close LOG;

      Caution: Contents may have been coded under pressure.
        Well okay, but I think the OP wanted to partition messages by type, not count instances. So to perlify further:

        my %messages = map { $_ => [] } qw(error alert warning); my $logfile = '/var/log/messages'; open my $log, "<", $logfile or die "$logfile: open: $!"; while (<$log>) { for my $type (keys %messages) { push @{ $messages{$type} }, $_ if /$type/; } } close $log or die "$logfile: close: $!"; # as long as we're bothering +with explicit close, we may as well test it for success.

        I know you know it, but there's no reason to \Q the type names here since they don't contain dangerous characters.

Re: Not exactly Dereferencing... but in that ball park
by davis (Vicar) on Nov 19, 2005 at 15:17 UTC
    The thing you're trying to do is known as "symbolic referencing", and yes, it can be done. You don't want to do it though (there are plenty of nodes around that can tell you why). One better way of doing this would be to use a hash:
    use warnings; use strict; use Data::Dumper; my $message_log = "/var/log/messages"; my %messages = ( error => {}, alert => {}, warning => {}, ); open(my $logfile, "<", $message_log) or die "Unable to open $message_log: $!\n"; foreach my $type (keys(%messages)) { seek $logfile, 0, 0; foreach my $line (<$logfile>) { $messages{$type} .= $line if($line =~ /$type/); } } close($logfile); print Dumper(\%messages);
    This probably isn't the most efficient algorithm for this type of thing, but it wouldn't surprise me if it was faster than your version using shell tools.

    davis
    Kids, you tried your hardest, and you failed miserably. The lesson is: Never try.
Re: Not exactly Dereferencing... but in that ball park
by ioannis (Abbot) on Nov 19, 2005 at 20:07 UTC
    Be careful with your lexical variables, besides the compilation errors.

    my ($error,$alert,$warning);

    All soft-references to ${'error'} in the program refer to global $::error, and not to the lexical variable $error. (Same observations for variables $alert and $warnings; therefore, there was no need to declare them since they are not used.)