audioslave audioslave -4 years ago 118
Perl Question

grep case-insensitively for a string in a text file

I'm writing a Perl script but I don't get a part of it.

There's a text file with host names, one per line.

I need to search a second file with host names (a blacklist) for the hostname read from the first one. To be sage the search should be done case insensitive.

My first approach was using the Perl

grep
, but I read about it and it seems not quite usable for what I needed it to. So I thought about using the shell
grep
.

As far as I know, it could be executed with
system
,
qx
, backticks and
open
.

I decided to use
system
, so that I can get the exit status code of the
grep
and use it in a
if
statement to do the rest of the work the script is intended to. My code looks like this (test script with the
grep
):

use strict;
use warnings;

my $blacklist_server = "de9899svc";
my $server = undef;
my $exit_value = undef;

open(SERVERLISTE,"/home/ansible/serverscan/scan_results/serverliste_22.02.17.txt") or die "$!";

OUTER: while (<SERVERLISTE>) {
$server = $_;

system("grep -i '\$server' /home/ansible/serverscan/black.list");
$exit_value = $? >> 8;
print "$exit_value\n";
}

close SERVERLISTE;


The problem is, that
$exit_value
is always 1, regardless of whether the host names match or not. So can somebody please tell me what I'm missing :)

Answer Source

The better question would be to ask how to get Perl's grep to do what you wanted. It is almost always a better route to write Perl code instead of creating a whole new shell process to do something simple like this. I am certain it is possible, but I cannot correct your misconceptions if you don't explain

The problem is that you don't use chomp to remove the line endings from the records you read from either of the files. Putting a newline in the middle of a shell command will terminate the command at that point, so it looks like grep -i '$server

I would build a hash of blacklisted servers, and check it for each server in the list

The code would look something like this. It uses the case folding fc operator to compare case-insensitively, and so requires the feature to be enabled

use strict;
use warnings 'all';
use feature qw/ fc say /;

use constant {
    SERVER_LISTE => '/home/ansible/serverscan/scan_results/serverliste_22.02.17.txt',
    BLACK_LISTE  => '/home/ansible/serverscan/black.list',
};

my %blacklist = do {
    open my $fh, '<', BLACK_LISTE or die $!;
    my @blacklist = <$fh>;
    chomp @blacklist;
    map { fc $_ => 1 } @blacklist;
};

open my $server_liste, '<', SERVER_LISTE or die $!;

while ( my $server = <$server_liste> ) {

    chomp $server;

    say "server $server is blacklisted" if $blacklist{ fc $server };
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download