Re: Compare values of two or more arrays

[email protected] (Rob Dixon)
Newsgroups perl.beginners
Message-ID <[email protected]>
Mimi Cafe wrote:
> I am trying to compare one or more lists against a master record file and
> find out elements of the master record which are not in the other records
> and compile new lists of elements which are in the master data, but not
> found in the other records.
> 
> This works to fine, but the output list is random to some extend. The script
> is run with command line arguments specifying the master data file and the
> other file(s) to compare:
> 
> script --master masterrecord.txt --compare compare_file1 --compare
> compare_file2

I'm not sure what your question is, or what you mean by 'the output list is
random'. But I can comment on your code.

> ##########################################
> 
> #!c:\perl\bin\perl.exe -w

The #! line is only noticed by Unix-type shells and is ignored completely on a
Windows platform, so it's best just to leave it off. (Perl itself still takes
note of the command line switches specified here and so still actions your -w,
but see below.).

> use strict;
> #use warnings;

It's always better to

  use warnings;

rather than using the -w command-line switch.

> #use diagnostics;
> use Getopt::Long;
> 
> # Perl script to compare WSUS and AV clients against AD computers and create
> a report of AD
> # computers not found in the WSUS or AV list.
> 
> use constant DEFAULT_REPORTDIR => 'CompareReport';
> #use constant DEFAULT_WORKINGDR => '.';
> my ($master, @compare, $help);
> 
> 
> Getopt::Long::Configure ("permute","ignorecase");
> 
> GetOptions(
>  "master=s" => \$master,
>  "compare:s" => \@compare,
>  "help|?!" => \$help,
> );
> 
> usage() if $help;
> 
> foreach (@compare){
>  die "File $_ does not exist or it's empty. Please check the file try
> again.\n" unless -s $_;
> }

If your die string ends with a newline then the output won't include the source
file and line number, which may be useful when you are debugging. Like this

  die "failed";

produces

  failed at E:\Perl\source\x.pl line 14.

while

  die "failed\n";

produces just

  failed

> my $outputdir = DEFAULT_REPORTDIR;
> unless (-d $outputdir){
>  mkdir ($outputdir) or die "could not create dir for $outputdir: $!\n";
> }

mkdir will only succeed if the parent directory exists. That is to say,

  mkdir 'path/to/my/directory';

will fail unless path/to/my exists.

It may be useful to take a look at the mkpath function in File::Path, which will
also create any intermediate directories in the path.

> # Read the master list and populate our array.
> open (MASTERFILE, "<", $master) or die "Could not open $master for reading:
> $!\n";
> my @master_clients = <MASTERFILE>;
> chomp(@master_clients);
> close MASTERFILE;

It is better to use lexical file handles, as in

  open my $masterfh, '<', $master or die "Could not open $master for reading: $!";

If I was writing this I would say

  my @master_clients = do {
    open my $fh, '<', $master or die "Could not open $master for reading: $!";
    <$fh>;
  };
  chomp @master_clients;

> my (%inputclient,$list);

It is always best to declare variables as close as possible to the point of use.
Declaring %inputclient here means that the contents the files in @compare will
be accumulated to the hash, and when you are processing the last file in the
list your output will show only those values that are in /none/ of the files in
the list. Is this what you mean by the output list being random?

I'm fairly certain that you want a per-file report, ans so the hash should be
declared within this for loop.

> # Read the other files and compare the content to the master client list.
> foreach $list (@compare){

foreach my $list (@compare) {

>  # Output file name set of element curerently processed.
>  # Open file to read from.
> 
>  open(INFH, "$list") or warn "Could not open $list for reading: $!\n";

This will give you a warning but still continue to use an invalid file handle.

>  while (<INFH>){
>    chomp;
>    $inputclient{"$_"} = $_;
>  }
>  close INFH;

  {
    open my $fh, '<', $list or do {
      warn "Could not open $list for reading: $!";
      next;
    };

    while (<$fh>) {
      chomp;
      $inputclient{$_}++;
    }
  }

>  my $outputfile = $list;
>  my (@missing_clients, %outputclient);
> 
>   foreach my $aditem (@master_clients){
>   push (@missing_clients, $aditem) unless exists $inputclient{"$aditem"};
>  }
> 
> 
>  open (OUTPUTFILE, ">$outputdir\\$outputfile") || die "Could not open
> $outputfile: $!\n";
>  foreach (@missing_clients){ print OUTPUTFILE "$_\n";}
>  close (OUTPUTFILE);

  {
    open my $fh, '>', "$outputdir\\$list";
    print $fh "$_\n" foreach @missing_clients;
  }

> }
> 
> 
> # Subroutine to print example of script usage.
> 
> sub usage {
>  print "\nUSAGE:\t$0 --master master_file --comapre file1 --comapre
> file2\n\n";
>  print "\tExample: $0 --master adlist --compare avlist --comapre file2\n";
>  print "\t$0 --help or --? should displays this usage summary.\n";
>  exit;
> 
> }

HTH,

Rob
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.