Still trying to get a grep -c that works

I am trying to get a count of each line

sub runit2 {
my ($file1a, $file2a) = @;
my $file1_vala = $file1a->get;
my $file2_vala = $file2a->get;
open (FILE1a, "$file1_vala") or die;
open (FILE2a, "$file2_vala") or die;
chomp(my @strings = <FILE2a>);
while (1) {
foreach $pattern (<FILE1a>) {
chomp($pattern);
last if $pattern =~ /^\s*$/;
my @matches = eval {
grep $pattern eq $
, @strings;
};
if ($@) {
print "Error: $@";
} else {
my $count = @matches;
print "$count $pattern \n",
#$text->insert('end', "$count $pattern $_\n");
}
}
return;
}

1 ip routing
1 ip classless
1 no ip bootp server
1 no ip http server
1 no ip http secure-server
1 ip bgp-community new-format
1 no access-list 23
1 no access-list 51
1 logging buffered 4096 debugging
1 banner motd ^
6 *************************************************
6**************************************************
2 ^
1 banner exec ^
6**************************************************
2 * LEGAL NOTICE *
6 ***************************************************
6 ***************************************************
2 * LEGAL NOTICE *
6 ****************************************************
2 ^
1 ip dhcp excluded-address 10.8.26.1 10.8.26.100
1 ip dhcp excluded-address 10.8.26.200 10.8.26.254
1 no auto-summary
1 snmp-server view BLOCK iso included
1 snmp-server view BLOCK ipAddrEntry.*.*.*.*.* included
1 snmp-server view BLOCK ipAddrEntry.*.10.*.*.* excluded
1 snmp-server view BLOCK ipNetToMediaEntry.*.*.*.*.*.* included
1 snmp-server view BLOCK ipNetToMediaEntry.*.*.10.*.*.* excluded
1 snmp-server view BLOCK atEntry.*.*.*.*.*.*.* included
1 snmp-server view BLOCK atEntry.*.*.*.10.*.*.* excluded
2 snmp-server ifindex persist
2 snmp-server enable traps snmp authentication linkdown linkup coldstart warmstart
1 snmp-server enable traps frame-relay
1 snmp-server enable traps frame-relay subif
1 snmp-server enable traps config
1 ip tacacs source-interface loopback0
1 snmp-server trap-source loopback0
1 ip flow-export source fa0/0
1 ip flow-export version 5 origin-as
1 ip flow-export destination 10.15.1.2 9996
1 ip flow-cache timeout active 1
1 ip flow-cache timeout inactive 15
2 snmp-server ifindex persist
1 logging trap notifications
1 logging source-interface fa0/0
2 snmp-server enable traps snmp authentication linkdown linkup coldstart warmstart
1 privilege exec level 1 traceroute
1 privilege exec level 1 ping
1 privilege exec level 1 show configuration
1 line con 0
2 exec-timeout 5 0
3 login
1 line aux 0
2 exec-timeout 5 0
3 login
1 line vty 0 4
1 exec-timeout 30 0
1 no privilege level 15
1 no access-class 23 in
3 login
1 end

The easiest thing to look at is the 3 login lines. login appears in file 2 3 times. I only want a single output of "3 login" and not that statement every time the script encounters login.

You still want to drop the eval. Trust me on this, it's not doing anything useful.

Save the matches to a hash and print it only at the end. One of the earlier threads where you asked about this had a solution which did that.

foreach $pattern (<FILE1a>) {
  chomp($pattern);
  last if $pattern =~ /^\s*$/;
  my $matches = grep $pattern eq $_, @strings;
  ++$count{$pattern} if $matches;
}

for my $key (keys %count) {
  print "$count{$key} $key\n";
}

You need to declare %count up at the top if you use strict (which you should). Also the initialization before the for loop can stay as before. The endless while loop I don't understand; what's that for? Also you should probably close your files when you're done with them, especially if this is going to be a subroutine in a bigger program.

Here is the exact sub that I now have in the script

#***********************
sub runit2 {
my ($file1a, $file2a) = @;
my $file1_vala = $file1a->get;
my $file2_vala = $file2a->get;
open (FILE1a, "$file1_vala") or die;
open (FILE2a, "$file2_vala") or die;
$text->insert('end', "Device config contains: \n");
chomp(my @strings = <FILE2a>);
while (1) {
foreach $pattern (<FILE1a>) {
chomp($pattern);
last if $pattern =~ /^\s*$/;
my @matches = eval {
#grep /$pattern/, @strings;
grep $pattern eq $
, @strings
};
if ($@) {
print "Error: $@";
} else {
my $count = @matches;
$text->insert('end', "$count $pattern \n");
}
}
return;
}
close FILE1a;
close FILE2a;
}

If I take out the infinite while loop, the output is

"Device config contains:
1 no service tcp-small-servers"

Thats it, no further iteration.

If I leave it in, a snip of the output which is really not desirable ...

.
.
.
.
.
2 snmp-server enable traps snmp authentication linkdown linkup coldstart warmstart
1 snmp-server enable traps frame-relay
1 snmp-server enable traps frame-relay subif
1 snmp-server enable traps config
1 ip tacacs source-interface loopback0
1 snmp-server trap-source loopback0
1 ip flow-export source fa0/0
1 ip flow-export version 5 origin-as
1 ip flow-export destination 10.15.1.2 9996
1 ip flow-cache timeout active 1
1 ip flow-cache timeout inactive 15
2 snmp-server ifindex persist
1 logging trap notifications
1 logging source-interface fa0/0
2 snmp-server enable traps snmp authentication linkdown linkup coldstart warmstart
1 privilege exec level 1 traceroute
1 privilege exec level 1 ping
1 privilege exec level 1 show configuration
1 line con 0
2 exec-timeout 5 0
3 login
1 line aux 0
2 exec-timeout 5 0
3 login
1 line vty 0 4
1 exec-timeout 30 0
1 no privilege level 15
1 no access-class 23 in
3 login
1 end

If I modify the code above to

#***********************
sub runit2 {
my ($file1a, $file2a) = @;
my $file1_vala = $file1a->get;
my $file2_vala = $file2a->get;
open (FILE1a, "$file1_vala") or die;
open (FILE2a, "$file2_vala") or die;
$text->insert('end', "Device config contains: \n");
#*******************************
foreach $pattern (<FILE1a>) {
chomp($pattern);
last if $pattern =~ /^\s*$/;
my $matches = grep $pattern eq $
, @strings;
++$count{$pattern} if $matches;
}

for my $key (keys %count) {
print "$count{$key} $key\n";
}
#*******************************
close FILE1a;
close FILE2a;
}

I would expect the hash to be printed in the "dos" window.

If the following is included, I get very many errors.

use strict
%count = ();

If omitted, nothing is printed to the dos window, but it does run.

Sorry ...

This line is also included in sub ..

chomp(my @strings = <FILE2a>);

Hosed my cut and paste.

When you use strict, all of your code needs to be strict. It's a hassle at first but it's useful when you start getting useful warnings when the code doesn't do what you expect. If your code is not strict, tackle that later. But adopt it in the next script you write. It's good for you.

The last will quit the foreach loop on the first blank or empty line. If you have empty lines in the patterns file, you probably mean "next", not "last".

If you have the same pattern multiple times in the pattern file, you will get multiple prints of the count of matches. I was under the impression that you were getting 1 login 2 login 3 login but now I see that you have 3 login 3 login 3 login, so it's simply reporting the same pattern multiple times. Welp, you can use a hash to prevent that, too.

sub runit2 {
  my ($file1a, $file2a) = @_;
  my $file1_vala = $file1a->get;
  my $file2_vala = $file2a->get;
  open (FILE1a, "$file1_vala") or die;
  open (FILE2a, "$file2_vala") or die;
  chomp(my @strings = <FILE2a>);
  close FILE2a;
  $text->insert('end', "Device config contains: \n");
  #*******************************
  foreach $pattern (<FILE1a>) {
    next if $pattern =~ /^\s*$/;
    next if $handled{$pattern};
    $handled{$pattern} = 1;
    chomp($pattern);
    my $matches = grep $pattern eq $_, @strings;
    next unless $matches;
    $text->insert('end', "$matches $pattern \n");
  }
  close FILE1a;
}