jackie
jackie

Reputation: 644

Checking for Duplicates in array

What's going on:

I've ssh'd onto my localhost, ls the desktop and taken those items and put them into an array.

I hardcoded a short list of items and I am comparing them with a hash to see if anything is missing from the host (See if something from a is NOT in b, and let me know).

So after figuring that out, when I print out the "missing files" I get a bunch of duplicates (see below), not sure if that has to do with how the files are being checked in the loop, but I figured the best thing to do would be to just sort out the data and eliminate dupes.

When I do that, and print out the fixed data, only one file is printing, two are missing.

Any idea why?

#!/usr/bin/perl

my $hostname = $ARGV[0];

my @hostFiles = ("filecheck.pl", "hostscript.pl", "awesomeness.txt");
my @output =`ssh $hostname "cd Desktop; ls -a"`;

my %comparison;
for my $file (@hostFiles) {
    $comparison{$file} +=1;
}

for my $file (@output) {
    $comparison{$file} +=2
}

for my $file (sort keys %comparison) {
    @missing = "$file\n" if $comparison{$file} ==1;
    #print "Extra file: $file\n" if $comparison{$file} ==2;
    print @missing;
}

my @checkedMissingFiles;

foreach my $var ( @missing ){
    if ( ! grep( /$var/, @checkedMissingFiles) ){
        push( @checkedMissingFiles, $var );
    }
}
print "\n\nThe missing Files without dups:\n @checkedMissingFiles\n";

Password:

awesomeness.txt ##This is what is printing after comparing the two arrays
awesomeness.txt
filecheck.pl
filecheck.pl
filecheck.pl
hostscript.pl
hostscript.pl

The missing Files without dups: ##what prints after weeding out duplicates hostscript.pl

Upvotes: 1

Views: 427

Answers (3)

RickF
RickF

Reputation: 1822

It seems to me that looping over the 'required' list makes more sense - looping over the list of existing files isn't necessary unless you're looking for files that exist but aren't needed.

#!/usr/bin/perl
use strict; 
use warnings;
my @hostFiles = ("filecheck.pl", "hostscript.pl", "awesomeness.txt");
my @output =`ssh $ARGV[0] "cd Desktop; ls -a"`;
chomp @output;
my @missingFiles;
foreach (@hostFiles) {
  push( @missingFiles, $_ ) unless $_ ~~ @output;
}
print join("\n", "Missing files: ", @missingFiles);

Upvotes: 1

Sorin
Sorin

Reputation: 5415

The perl way of doing this would be:

#!/usr/bin/perl -w

use strict;
use Data::Dumper;
my %hostFiles = qw( filecheck.pl 1 hostscript.pl 1 awesomeness.txt 1);
# ssh + backticks + ls, not the greatest way to do this, but that's another Q
my @files =`ssh $ARGV[0] "ls -a ~/Desktop"`;
# get rid of the newlines 
chomp @files;
#grep returns the matching element of @files
my %existing = map { $_ => 1} grep {exists($hostFiles{$_})} @files;
print Dumper([grep { !exists($existing{$_})} keys %hostFiles]);

Data::Dumper is a utility module, I use it for debugging or demonstrative purposes.

If you want print the list you can do something like this:

{
    use English;
    local $OFS = "\n";
    local $ORS = "\n";
    print grep { !exists($existing{$_})} keys %hostFiles;
}

$ORS is the output record separator (it's printed after any print) and $OFS is the output field separator which is printed between the print arguments. See perlvar. You can get away with not using "English", but the variable names will look uglier. The block and the local are so you don't have to save and restore the values of the special variables.

If you want to write to a file the result something like this would do:

{
    use English;
    local $OFS = "\n";
    local $ORS = "\n";
    open F, ">host_$ARGV[0].log";
    print F grep { !exists($existing{$_})} keys %hostFiles;
    close F;
}

Of course, you can also do it the "classical" way, loop trough the array and print each element:

open F, ">host_$ARGV[0].log";
for my $missing_file (grep { !exists($existing{$_})} keys %hostFiles) {
    use English;
    local $ORS = "\n";
    print F "File is missing: $missing_file"
}
close F;

This allows you to do more things with the file name, for example, you can SCP it over to the host.

Upvotes: 2

kbenson
kbenson

Reputation: 1464

@missing = "$file\n" assigns the array @missing to contain a single element, "$file\n". It does this every loop, leaving it with the last missing file.

What you want is push(@missing, "$file\n").

Upvotes: -1

Related Questions