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

The code im posting has some issues - I know. My end goal is to have output something like this:
[printer_queue1] [user1] 5 jobs - 10 pages total [user2] 2 jobs - 1 page total [printer_queue2] [userx] 100 jobs - 300 pages total
This is the code I have so far
use strict; use warnings; use diagnostics; use Data::Dumper; open PAGELOG, "page_log" or die "unable to open pagelog: $!\n"; my %unique=(); my (@array, @queues); my @LOGLINES=map { split /^(.*)$/, $_ } <PAGELOG>; # Get all unique queue names for (@LOGLINES) { next unless /^\w+.*/; my $queue=$1 if /^(\w+)\s.*/; push (@queues, $queue) unless $unique{$queue}++; } for my $line(@LOGLINES) { chomp ($line); next unless ( $line =~ m/^\w+.*/ ); for my $queue (@queues) { chomp ($queue); next unless ($queue =~ m/\w+/); if (grep $queue, $line) { s/$1//g if ($line =~ m/.*(\[.*\])\s.*/); s/$1/ /g if ($line =~ m/^\w.*(\s\s).*/); my ($printer, $user, $jid, $page, $copies, $billing, $host +) = split(/ /, $line); push ( @array,[$queue, $user, $jid]) unless $unique{$jid}+ ++; } } } print Dumper @array;
one issue im having is the following line
s/$1/ /g if ($line =~ m/^\w.*(\s\s).*/);
is producing this error
Use of uninitialized value in substitution (s///) at C:\Documents and Settings\Ted\Desktop\perl\cups
.pl line 36, <PAGELOG> line 192.
although the value of @array printed to Dumper looks promising, Im having trouble getting to my final goal. here is a sample of the page_log.
R_NETADMIN_NB apache 8 [22/Apr/2005:11:19:55 -0400] 1 1 - localhost R_NETADMIN_NB apache 9 [22/Apr/2005:12:53:19 -0400] 1 1 - localhost R_SPARE root 15 [25/Apr/2005:13:12:58 -0400] 1 1 - localhost R_SPARE root 15 [25/Apr/2005:13:15:00 -0400] 1 1 - localhost R_NETADMIN_NB apache 13 [25/Apr/2005:14:47:15 -0400] 1 1 - localhost R_SPARE root 15 [25/Apr/2005:14:47:27 -0400] 1 1 - localhost RSPARE root 16 [25/Apr/2005:14:53:52 -0400] 1 1 - localhost RSPARE_NB root 17 [25/Apr/2005:14:57:41 -0400] 1 1 - localhost RSPARE root 16 [25/Apr/2005:14:58:07 -0400] 1 1 - localhost R_NETADMIN_NB root 18 [25/Apr/2005:14:59:08 -0400] 1 1 - localhost R_NETADMIN_NB root 19 [25/Apr/2005:15:00:37 -0400] 1 1 - localhost Y_NETADMIN root 20 [25/Apr/2005:15:13:16 -0400] 1 1 - localhost Y_NETADMIN root 20 [25/Apr/2005:15:13:18 -0400] 1 1 - localhost Y_NETADMIN_NB root 21 [25/Apr/2005:15:14:21 -0400] 1 1 - localhost

Im not too sure what steps to take next.
Thanks in advance

UPDATE
Thanks! I worked longer than I needed to on this. Thanks for your suggestions! I learn new/better ways to do things here every day - my perl coding has improved vastly over the past few months from the suggestions and examples I have gotten here - I only hope I can offer someone this kind of help someday... I still have much to learn.

Ted
--
"Men have become the tools of their tools."
  --Henry David Thoreau

Replies are listed 'Best First'.
Re: combining elements of arrays
by jdporter (Paladin) on May 12, 2005 at 04:02 UTC
    I'm not sure why you're making it so complicated. Maybe I'm missing something.
    my %q_u; open PAGELOG, "< page_log" or die "unable to open pagelog for read: $!\n"; while (<>) { chomp; my( $queue, $user, $jobid, @rest ) = split; defined $jobid or next; $q_u{$queue}{$user}{'jobids'}{$jobid}++; $q_u{$queue}{$user}{'npages'}++; } close PAGELOG; for my $queue ( sort keys %q_u ) { print "[$queue]\n"; for my $user ( sort keys %{ $q_u{$queue} } ) { my $nj = keys %{ $q_u{$queue}{$user}{'jobids'} }; my $np = $q_u{$queue}{$user}{'npages'}; print " [$user]\n"; print " $nj jobs - $np pages total\n"; } }
      Excellent! Thanks - I usually complicate things like this.

      Ted
      --
      "Men have become the tools of their tools."
        --Henry David Thoreau
Re: combining elements of arrays
by jhourcle (Prior) on May 12, 2005 at 03:54 UTC

    Much of the type of logic that you're looking for is found in the log reduction program 'LogWatch' (although, some of that code is particularly bad... don't try to turn on 'use strict' or 'use warnings' without a whole lot of free time).

    Anyway, the error you mention:

    s/$1/ /g if ($line =~ m/^\w.*(\s\s).*/);

    Is because that if you use s/// without specifying what it's acting on, it acts on $_. I'm guessing you wanted it to use $line :

    $line =~ s/$1/ /g if ($line =~ m/^\w.*(\s\s).*/);
Re: combining elements of arrays
by graff (Chancellor) on May 12, 2005 at 04:07 UTC
    Leaving aside other issues that this script might have, the immediate, short answer to your question is that you don't want statements like this:
    s/$1//g if ($line =~ m/.*(\[.*\])\s.*/); s/$1/ /g if ($line =~ m/^\w.*(\s\s).*/);
    For one thing, the "s/.../.../" as written there is applying to $_, not to $line, which is where I think you want it to apply.

    It would be better to write these as:

    $line =~ s/\[[^]]+\]//g; $line =~ s/\s+(?=\S)/ /g;
    There are more verbose, "less optimized" ways that might look less obscure (hence be worth the extra keystrokes or cpu cycles) -- e.g.:
    $line =~ s/ \[ .*? \] //gx; # remove strings enclosed by "[..]" $line =~ s/ \s+ (\S) / $1/gx; # normalize line-internal whitespace
    (update: had to add the "g" modifiers on those substitutions)

    Please refer to "perldoc perlre" for anything in those examples that you don't understand. (Hint: the "(?=...)" is referred to as a "zero-width look-ahead assertion".)

    In any case, the message you're getting isn't really an "error" -- it is a "warning", provided to you because you asked to get warnings, and because it describes a situation where you might want to double check to see whether it really matters that an uninitialized value is being used in a particular operation on a given line in your code.

    (There are cases where it's actually okay to use uninitialized values in places that trigger warnings -- but it usually doesn't hurt much to have perl draw your attention to such cases, especially during development.)

    What really matters is whether the output is what you want it to be. Is it?

Re: combining elements of arrays
by Errto (Vicar) on May 12, 2005 at 03:55 UTC

    I think the issue is probably this: the line you quoted is substituting a pair of spaces for a single space in the variable $_, not the variable $line, because you forgot to specify which variable the substitution applies to. More likely you meant this:

    $line =~ s/$1/ /g if ($line =~ m/^\w.*(\s\s).*/);
    although you could write that much more easily as
    $line =~ s/\s\s/ /g;
    or even
    $line =~ s/\s{2,}/ /g;
    if your intent is actually to reduce all sequences of spaces to a single space.

    Update: For those who notice, yes, it's true my first suggested alternative does not exactly match the semantics of the OP. Specifically, if $line contains one sequence of a tab followed by a space, and a later sequence of two spaces, my substitution will touch that second sequence and the OP's won't, but I'll venture to guess that mine is closer to the intent.