schwende has asked for the wisdom of the Perl Monks concerning the following question:

Perl beginner here. I have an existing code, that was written some years ago. Basically, the code is used to peruse a database of names, and extract certain ones, based on their roles. That part works fine. Occasionally, I want to exclude certain names, so this script is supposed to reference an exclusion file. This is where it goes south. I get no errors, so it's like it can "see" the file, but doesn't actually read it. Obviously, it would be helpful to learn Perl, so I know what I am doing, and understand it; but for the short term I'd like to just fix the problem that is occurring. I shall attempt to paste my code. I have no idea what OS it was originally written on, but was used on rhel 6, and is now on a rhel 7 server. My guess as to why it no longer works, is because the current version of perl is newer, and so the code doesn't quite work the same. I currently have 5.16.3, which isn't exactly new, either. I've tried debugging, but I get no errors, at least nothing that stands out as an error.
#!/usr/bin/perl -w use strict; use Net::LDAP; use Time::Piece; if ($#ARGV < 0) { print STDERR "Usage: ./everyone.pl pwd\n"; exit 1; } my $host = "ldap1.server.com:1000"; my $bindcred = $ARGV[0]; my $binddn = "cn=Directory Manager"; my $basedn = "ou=People,dc=server,dc=com"; my $dateout = Time::Piece->new->strftime('%Y%m%d'); my $infile = "output/$dateout/everyone.list"; open(OUTFILE, ">", $infile) or die("Can't open $infile.clean for outpu +t"); my $ldap = Net::LDAP->new($host, timeout=>2) || SYSerror("New", "Couldn't connect to $host"); my $mesg = $ldap->bind("$binddn", password=>"$bindcred"); if ($mesg->is_error) {LDAPerror("Bind", $mesg);} my $result = $ldap->search(base=>"$basedn", scope=>"sub", filter=>"(&(|(servercomBannerRole=Student)(servercomBannerRole=Facul +ty)(&(servercomBannerRole=Staff)(!(servercomBannerRole=Villagestaff)) +)))", attrs=>["mail","cn"]); if ($result->is_error) {LDAPerror("Search", $result);} my @entries = $result->entries; my $mExcludingFile = "excludes/everyone.txt"; my $includingFile = "includes/everyone.txt"; my @mArray = (); my $mLine; my $mCountAll = 0; my $mCountOrig = 0; my $mCountAdd = 0; my $mCountDel = 0; open(ROFILE, "<", $mExcludingFile) or die("Can't open $mExcludingFile +exception file!"); while(<ROFILE>) { push(@mArray, $_); } close(ROFILE); my $mArrayNow; my $entry; foreach $entry(@entries) { my $name = $entry->get_value("cn"); my $email = $entry->get_value("mail"); my $mLineNow = "$email $name\n"; my $mOkay = 1; $mCountOrig++; foreach $mArrayNow (@mArray) { if ($mLineNow eq $mArrayNow) { $mOkay = 0; } } if ($mOkay == 1) { print OUTFILE $mLineNow; } else { $mCountDel++; } } flock(OUTFILE, 8); close(OUTFILE); open(OUTFILE, ">>", $infile); open(EXCEPTF, "<", $includingFile) or die("Can't open $includingFile i +nclusion file!"); while(<EXCEPTF>) { print OUTFILE $_; $mCountAdd++; } flock(OUTFILE, 8); close(OUTFILE); close(EXCEPTF); $mCountAll = $mCountOrig + $mCountAdd - $mCountDel; print "Ok.. Generated ".$mCountAll." (".$mCountOrig." + ".$mCountAdd. +" - ".$mCountDel.")\n"; sub LDAPerror { my ($from, $mesg) = @_; print "Error: " . $mesg->code . " (" . $mesg->error_name . ")\n"; print $mesg->error_text . "\n"; } sub SYSerror { my ($from, $mesg) = @_; print "Error: $mesg\n"; print "Source: $from\n"; die "$@"; }

Replies are listed 'Best First'.
Re: script runs, but doesn't appear to call file
by Corion (Patriarch) on Jul 17, 2023 at 17:26 UTC

    The script has misleading names ($infile is the name of an output file), but I think the likely problem stems from a change in the format of the exclusion file:

    open(ROFILE, "<", $mExcludingFile) or die("Can't open $mExcludingFile +exception file!"); while(<ROFILE>) { push(@mArray, $_); } ...

    Here, $_ contains the newline from each line in the file. If the file is formatted with Windows-style newlines (\r\n), it will contain \r\n at the end of each line. These lines are collected in the @mArray array (which would likely have better been named @exclusionList or something).

    ... my $mLineNow = "$email $name\n"; ... foreach $mArrayNow (@mArray) { if ($mLineNow eq $mArrayNow) {

    Here, the $mLineNow is built up and a Unix-style newline is added. If the exclusion file was formatted with Windows newlines, these lines will never be identical.

    My approach would be to first check if the difference in whitespace is the reason:

    xxd excludes/everyone.txt

    Check for 0d 0a sequences. If these show up, the file has Windows-style newlines.

    I would then modify the code to strip all whitespace from the lines:

    open(ROFILE, "<", $mExcludingFile) or die("Can't open $mExcludingFile +exception file!"); while(<ROFILE>) { s/\s+$//; push(@mArray, $_); }
    ...
    my $mLineNow = "$email $name"; # no newline needed here
Re: script runs, but doesn't appear to call file
by haukex (Archbishop) on Jul 17, 2023 at 17:36 UTC

    First, please see Short, Self-Contained, Correct Example - boiling down the code to the minimum needed to reproduce the problem both helps you narrow it down, and it helps us to have less irrelevant code to go through. Also, providing sample input with the expected output would be greatly helpful here.

    Second, please see the Basic debugging checklist - I suspect items 3 and 4 may apply here. I would recommend Data::Dump or Data::Dumper with $Data::Dumper::Useqq=1;.

    The reason is that I think this could be a line ending issue. I see you're not chomping your lines on input, which I would suggest you change, and if you do that you'll have to add a newline ("\n") when printing the lines back out. Corion already mentioned the possible Windows vs. Linux line endings issue.

    There are quite a few other things about the code that could use an overhaul, such as bareword filenames and an unchecked open ("open" Best Practices), seemingly pointless flock calls, predeclaring variables when their scope could and should be limited, but at the moment it doesn't look to me like those are causing the issue.

Re: script runs, but doesn't appear to call file
by schwende (Initiate) on Jul 18, 2023 at 14:49 UTC
    Well, to update on this. I did make a few small tweaks to the script, nothing major. What I found out is that I needed to add more info to the exclusion file. Basically, in the past, I could just add the email of the person I wanted to exclude. For whatever reason, I now have to add the email and name associated with the email. Such a simple thing, but it didn't occur to me, since I never had to do that before. It was just whim that I decided to try that. I can only attribute this, most likely, to a perl upgrade. I suppose it could have been os related, but I suppose it doesn't matter. Thank you for the replies. Now I can work at understanding how perl operates, better.