CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Intermediate:
One Line at a Time Please

 



rfransix
Novice

Jun 17, 2010, 12:42 PM

Post #1 of 12 (1241 views)
One Line at a Time Please Can't Post

Grateful for your expertise. This code erractically outputs to OUT.

Where should chomp; go in this example?

Both PERSON and MGR have an equal number of lines. The desired result is:

line1 from PERSON
changetype: modify
replace: manager
line1 from MGR

line2 from PERSON
changetype: modify
replace: manager
line2 from MGR

...etc...


#! perl -slw
use strict;
use warnings;
use diagnostics;
use constant batchdir => "c:\temp10";

open (PERSON,"f1");
open (MGR,"f2");
open OUT, ">", "buildAD.ldif" or die "Cannot write to 'buildAD.ldif': $!";
truncate (OUT, 0);

my $line;
my $line2;

while ($line = <PERSON>) {
#chomp;
my @dn1 = split(/\s+/,$line);
my $count = scalar(@dn1);
print OUT "$line";
print OUT "changetype: modify";
print OUT "replace: manager";

while ($line2 = <MGR>) {
#chomp;
my @dn2 = split(/\s+/,$line2);
my $count2 = scalar(@dn2);
print OUT $line2, "\n", if ($count == $count2);
}
}

close PERSON;
close MGR;
close OUT;
exit;


Example data in OUT is here, the extra newline on line 2 should not be there, and all the numbers after 282150 are from <MGR>.

0104

changetype: modify
replace: manager
2821


3682


1129


2050


4054


0755


BillKSmith
Veteran

Jun 17, 2010, 2:33 PM

Post #2 of 12 (1234 views)
Re: [rfransix] One Line at a Time Please [In reply to] Can't Post

The file "f1" probably did not open. Use the three argument form of open and check for errors on input as well as output.



You never use the constant batchdir. If you did, it would not work. There are at least three ways to fix the problelm with the back-slash.

1) Use slash instead. Windows will understand.

2) Use single quotes rather than double. Back-slash is not a special character under single quotes.

or

3) Escape the back-slash with another back-slash.



The extra newline comes from your print statement.
Good Luck,
Bill


rfransix
Novice

Jun 18, 2010, 7:52 AM

Post #3 of 12 (1216 views)
Re: [BillKSmith] One Line at a Time Please [In reply to] Can't Post

Grateful for your expertise, I have update the code without effect. The first line in OUT is the first line from F1. Unfortunately, it's the only line from F1.

While the newline is caused by ,,print", how can it be removed, it is not wanted Wink

So, ,,use constant batchdir" is not implicit throughout the script; then how should it be used in this case?

Overall, the most important objective is to understand why the 2 while statements are not iteratating line-by-line.


FishMonger
Veteran / Moderator

Jun 18, 2010, 8:26 AM

Post #4 of 12 (1213 views)
Re: [rfransix] One Line at a Time Please [In reply to] Can't Post

Please, ALWAYS use the code tags when posting your code.

Why are you using the -slw switches? Remove them, they are not needed.

Use the 3 arg form of open and a lexical var for the filehandle instead of the bareword.

ALWAYS check the return code of an open call to verify that it was successful and take action if it wasn't.


Code
open my $person_fh, '<', "f1" or die "failed to open 'f1' $!";



There's no reason to have that truncate statement.

Vars should be declared in the smallest scope that they require and the var names should be descriptive.
e.g., change:

Code
my $line; 

while ($line = <PERSON>) {

to:

Code
while ( my $person = <$person_fh> ) {


Using the nested while loops is not what you want. When the outer loop processes the first line, the inner loop will process the entire "f2" file before outer loop moves on to the second line.


(This post was edited by FishMonger on Jun 18, 2010, 8:27 AM)


BillKSmith
Veteran

Jun 19, 2010, 3:49 PM

Post #5 of 12 (1196 views)
Re: [rfransix] One Line at a Time Please [In reply to] Can't Post


In Reply To

While the newline is caused by ,,print", how can it be removed, it is not wanted Wink

Remove "\n" from print if llines equal.

In Reply To

So, ,,use constant batchdir" is not implicit throughout the script; then how should it be used in this case?

constant has nothing to do with directories. It is used to simulate a readonly variable. Unfortunately it does not expand in a quoted string. Use Readonly module instead. You should either prepend the path names to your files names or use chdir to change the working directory.

In Reply To
Overall, the most important objective is to understand why the 2 while statements are not iteratating line-by-line.

See FishMonger's reply.

Good Luck,
Bill


rfransix
Novice

Jun 21, 2010, 2:34 PM

Post #6 of 12 (1166 views)
Re: [BillKSmith] One Line at a Time Please [In reply to] Can't Post

Grateful for your guidance. The extra line is after the read of the first line in f1; the \n is placed after the manager: value line, so it doesn't make sense that the newline is inserted from \n.

Also FishMongers's guidance has not resulted in successfully reading both files line-by-line. Here's the corrected code to try and simple read in each line from f1 and print out the next two print statements, then we can work on reading the 2nd file line by line:


Code
#! perl  
use strict;
use warnings;
use diagnostics;

open my $person_fh, "<", "f1" or die "Cannot read 'f1': $!";
open my $mgr_fh, "<", "f2" or die "Cannot read 'f2': $!";
open my OUT, ">", "buildAD.ldif" or die "Cannot write to 'buildAD.ldif': $!";

my $person;
my $person2;

while (my $person = <$person_fh>) {
chomp;
my @dn1 = split(/\s+/,$line);
my $count = scalar(@dn1);
print OUT "$person";
print OUT "changetype: modify";
print OUT "replace: manager";

#while ($line2 = <$MGR>) {
#chomp;
#my @dn2 = split(/\s+/,$line2);
#my $count2 = scalar(@dn2);
#print $OUT $line2, "\n", if ($count == $count2);
#}
}

close $person_fh;
close MGR;
close OUT;
exit;




BillKSmith
Veteran

Jun 21, 2010, 6:28 PM

Post #7 of 12 (1157 views)
Re: [rfransix] One Line at a Time Please [In reply to] Can't Post

All comment lines are correct except the while (and matching brace). Just rread one line.
Good Luck,
Bill


FishMonger
Veteran / Moderator

Jun 21, 2010, 9:23 PM

Post #8 of 12 (1153 views)
Re: [rfransix] One Line at a Time Please [In reply to] Can't Post


Quote
D:\perl>perl -c rfransix.pl
No such class OUT at rfransix.pl line 8, near "open my OUT"
syntax error at rfransix.pl line 8, near "my OUT,"
Global symbol "$line" requires explicit package name at rfransix.pl line 15.
rfransix.pl had compilation errors (#1)
(F) You provided a class qualifier in a "my", "our" or "state" declaration, but
this class doesn't exist at this point in your program.

BEGIN not safe after errors--compilation aborted at C:/Perl64/lib/Carp/Heavy.pm line 11.
Compilation failed in require at C:/Perl64/lib/Carp.pm line 33.



FishMonger
Veteran / Moderator

Jun 21, 2010, 9:29 PM

Post #9 of 12 (1152 views)
Re: [rfransix] One Line at a Time Please [In reply to] Can't Post


Quote

Code
while (my $person = <$person_fh>) {   
chomp;
my @dn1 = split(/\s+/,$line);



What var do you think chomp is being applied to?

$line was never declared/assigned


rfransix
Novice

Jun 22, 2010, 9:10 AM

Post #10 of 12 (1139 views)
Re: [FishMonger] One Line at a Time Please [In reply to] Can't Post

Grateful for you views and replies. However, we are not getting results, so, I've reverted to my original code, which actually does more of what is required. Unfortunately, the following error is preventing a successful result. Your answers are appreciated. I've declared $entry here: my $entry = $dn->pop_entry();
Thanks. I figure once the first ldap search and print statements are working, adding the 2nd ldap search will be a snap.


Code
#! perl 
use strict;
use warnings;
use diagnostics;

use Net::LDAP;
use Net::LDAP::Entry;
use Net::LDAP::Search;
use Net::LDAP::LDIF;

open PERSON, "<", "ou3" or die "Cannot open 'ou3': $!";
open MGR, "<", "ou8" or die "Cannot open 'ou8': $!";
open OUT, ">", "buildAD.ldif" or die "Cannot open 'buildAD.ldif': $!";


my $HOST = "11";
my $ADMIN = "cn=corp";
my $PWD = "0";
my $BASEDN = "dc=corp";

my $ldap = Net::LDAP->new("$HOST", port=>389) or die "$@";
my $dn = $ldap->bind("$ADMIN", password=>"$PWD");
my @attr = "1.1";
my $result = Net::LDAP::LDIF->new( "buildAD.ldif", "a", wrap=>40 );

while (<PERSON>){
chomp;
$dn = $ldap->search( #return only the employeeID DN
base => "$BASEDN",
filter => "(&(objectClass=user)(employeeID=$_))",
scope => "sub",
attrs => ['1.1']
);

my $entry = $dn->pop_entry();
$result->write_entry($entry);
print OUT "changetype: modify";
print OUT "replace: manager";
}

$dn = $ldap->unbind; #session ends

close OUT or die "Cannot close in-memory file: $!";
close MGR or die "Cannot close in-memory file: $!";
close PERSON or die "Cannot close in-memory file: $!";



C:\Temp10>c:\perl\bin\perl build4aa.pl
Use of uninitialized value $entry in concatenation (.) or string at
c:/Perl/site/lib/Net/LDAP/LDIF.pm line 506, <PERSON> line 2 (#1)
(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.



To help you figure out what was undefined, perl will try to tell you the
name of the variable (if any) that was undefined. In some cases it cannot
do this, so it also tells you what operation you used the undefined value
in. Note, however, that perl optimizes your program and the operation
displayed in the warning may not necessarily appear literally in your
program. For example, "that $foo" is usually optimized into "that "
. $foo, and the warning will refer to the concatenation (.) operator,
even though there is no . in your program.



Uncaught exception from user code:
Entry '' is not a valid Net::LDAP::Entry object. at build4aa.pl line 36
at c:/Perl/site/lib/Net/LDAP/LDIF.pm line 618
Net::LDAP::LDIF::__ANON__('Net::LDAP::LDIF=HASH(0x1edb774)', 'Entry \'\' is not a valid Net::LDAP::Entry object.') called at c:/Perl/
site/lib/Net/LDAP/LDIF.pm line 637
Net::LDAP::LDIF::_error('Net::LDAP::LDIF=HASH(0x1edb774)', 'Entry \'\' is not a valid Net::LDAP::Entry object.') called at c:/Perl/si
te/lib/Net/LDAP/LDIF.pm line 506
Net::LDAP::LDIF::_write_entry('Net::LDAP::LDIF=HASH(0x1edb774)', 0, undef) called at c:/Perl/site/lib/Net/LDAP/LDIF.pm line 473
Net::LDAP::LDIF::write_entry('Net::LDAP::LDIF=HASH(0x1edb774)', undef) called at build4aa.pl line 36


BillKSmith
Veteran

Jun 22, 2010, 11:54 AM

Post #11 of 12 (1130 views)
Re: [rfransix] One Line at a Time Please [In reply to] Can't Post

I suggest that you review your original post and FishMonger's first reply. That issue should be resolved.

All the error messages which you are now reporting come from the module Net::LDAP. You probably would get more advice if you started a new thread asking for help with that module. Explain exactly what you expect it to do.

Your latest idea of starting with a simple case is a good one. Can you simplify any more? Post a complete implementation of your simplified program. If it is necessary to use code you have already posted, either quote or link to it.
Good Luck,
Bill


rfransix
Novice

Jun 22, 2010, 1:09 PM

Post #12 of 12 (1125 views)
Re: [BillKSmith] One Line at a Time Please [In reply to] Can't Post

Thank. That is my goal as well. As I said, FishMongers recommendation, at the time, did not work. Focusing on this point in the code, I feel is the best use of our energy.

I agree, I'll post a new thread named One NET::LDAP line at a Time Please, for anyone following us.

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives