user4990635 user4990635 - 1 year ago 52
Perl Question

comparing two filename arrays for differences

below is my attempt and loading all filenames in a text file into an array and comparing that array to filenames which are in a seperate directory. I would like to identify the filenames that are in the directory and not in the file so I can then process those files. I am able to load the contents of the both directories succesfully but the compare operation is outputting all the files not just the difference.

Thank you in advance for the assistance.

use File::Copy;
use Net::SMTP;
use POSIX;
use constant DATETIME => strftime("%Y%m%d", localtime);
use Array::Utils qw(:all);
use strict;
use warnings;

my $currentdate = DATETIME;
my $count;
my $ErrorMsg = "";
my $MailMsg = "";
my $MstrTransferLogFile = ">>//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Mstr_Transfer_Log.txt";
my $DailyLogFile = ">//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Daily_Transfer_Log_" . DATETIME . ".txt";
my $InputDir = "//CFVFTP/Users/ssi/Transfer_Logs/folder1/";
my $MoveDir = "//CFVFTP/Users/ssi/Transfer_Logs/folder2/";
my $filetouse;
my @filetouse;
my $diff;
my $file1;
my $file2;
my %diff;

open (MSTRTRANSFERLOGFILE, $MstrTransferLogFile) or $ErrorMsg = $ErrorMsg . "ERROR: Could not open master transfer log file!\n";
open (DAILYLOGFILE, $DailyLogFile) or $ErrorMsg = $ErrorMsg . "ERROR: Could not open daily log file!\n";

#insert all files in master transfer log into array for cross reference
open (FH, "<//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Mstr_Transfer_Log.txt") or $ErrorMsg = $ErrorMsg . "ERROR: Could not open master log file!\n";
my @master = <FH>;
close FH;
print "filenames in text file:\n";
foreach $file1 (@master) { print "$file1\n"; }
print "\n";

#insert all 835 files in Input directory into array for cross reference
opendir (DIR, $InputDir) or $ErrorMsg = $ErrorMsg . "ERROR: Could not open input directory $InputDir!\n";
my @list = grep { $_ ne '.' && $_ ne '..' && /\.835$/ } readdir DIR;
print "filenames in folder\n";
foreach $file2 (@list) { print "$file2\n"; }
print "\n";

#get the all files in the Input directory that are NOT in the master transfer log and place into @filetouse array
@diff{ @master }= ();;
@filetouse = grep !exists($diff{$_}), @list;;

print "difference:\n";
foreach my $file3 (@filetouse) { print "$file3\n"; }

print DAILYLOGFILE "$ErrorMsg\n";
print DAILYLOGFILE "$MailMsg\n";


this is what the output looks like:

filenames in text file:

filenames in folder


Answer Source

This should help you to do what you need. It stores the names of all of the files in INPUT_DIR as keys in hash %files, and then deletes all the names found in LOG_FILE. The remainder are printed

This program uses autodie so that the success of IO operations needn't be checked explicitly. It was first available in Perl 5 core in v5.10.1

use strict;
use warnings qw/ all FATAL /;
use v5.10.1;
use autodie;
use feature 'say';

use constant LOG_FILE  => '//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Mstr_Transfer_Log.txt';
use constant INPUT_DIR => undef;

chdir INPUT_DIR;

my %files = do {
    opendir my $dh, '.';
    my @files = grep -f, readdir $dh;
    map { $_ => 1 } @files;

my @logged_files = do {
    open my $fh, '<', LOG_FILE;
chomp @logged_files;

delete @files{@logged_files};

say for sort keys %files;