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

I am trying to make a CSV file out of an LDAP output that comes from an external process.

Here is the structure of the output file:

cn: applegroup
member: CN=mem001,OU=Users,DC=myorg,DC=com
member: CN=mem002,OU=Users,DC=myorg,DC=com
member: CN=mem003,OU=Users,DC=myorg,DC=com
member: CN=mem004,OU=Users,DC=myorg,DC=com

cn: orangegroup
member: CN=mem301,OU=Users,DC=myorg,DC=com
member: CN=mem302,OU=Users,DC=myorg,DC=com
member: CN=mem303,OU=Users,DC=myorg,DC=com

And here is the code I have to read it:
#!/usr/bin/perl use strict; use warnings; # 0a) Initialize variables my $grpNm = ""; my $memID = ""; my @groupInfo = ("", ""); my @memberInfo = ("", ""); my @ldapMemInfo = ("", ""); my @idInfo = ("", ""); my @csvContent = ("", ""); my $allGroupResult = "allTmp.txt"; my $allGroupDataFinal = "allData.csv"; open my $fhGroupFile, '<', "$allGroupResult" or die "Could not create +or open $allGroupResult"; open my $fhCSVOutput, '>', "$allGroupDataFinal" or die "Could not crea +te or open $allGroupDataFinal"; sub lTrim { my $s=shift; $s =~ s/^\s+//; return $s; } sub rTrim { my $s=shift; $s =~ s/\s+$//; return $s; } sub trimAll { my $s=shift; $s =~ s/^\s+|\s+$//g; return $s; } # ------------ Main Program -------------------- while (<$fhGroupFile>) { my $line = $_; chomp $line; # Check if line begins with "cn" or "member" if ($line =~ m/^cn/) # found group name { @groupInfo = split /:/, $line; $grpNm = $groupInfo[1]; # second entry is group name $grpNm = lTrim($grpNm); #trim leading spaces from group name # print "array indice $groupInfo[1]\n"; print "scalar grpNm:$grpNm\n"; $csvContent[0] = $grpNm; } elsif ($line =~ m/^member/) # found member name { @memberInfo = split /:/, $line; @ldapMemInfo = split /,/, $memberInfo[1]; # second entry is full + string for ldap content @idInfo = split /=/, $ldapMemInfo[0]; # second entry is ldap con +tent #print "array idInfo /= @idInfo\n\n"; $memID = $idInfo[1]; # second entry is the specific ID #print "scalar memID = $memID\n"; $csvContent[1] = $memID; print $fhCSVOutput "$csvContent[0]"; print $fhCSVOutput ","; #print $fhCSVOutput "$csvContent[1]"; print $fhCSVOutput "\n"; } else { } } # while <$fhGroupFile> close($fhGroupFile); close($fhCSVOutput);

When I run it I get:
,pplegroup
,pplegroup
,pplegroup
,pplegroup
,rangegroup
,rangegroup

Before you ask, I get the same result if I use the scalar variables without the array @csvContent so,

print $fhCSVOutput "$csvContent[0]"; print $fhCSVOutput ","; #print $fhCSVOutput "$csvContent[1]"; print $fhCSVOutput "\n";

AND

print $fhCSVOutput "$grpNm"; print $fhCSVOutput ","; #print $fhCSVOutput "$memID"; print $fhCSVOutput "\n";

yield the same erroneous data.

Replies are listed 'Best First'.
Re: Strings overwrite themselves in print command
by hippo (Archbishop) on Jun 27, 2016 at 22:09 UTC

    It seems highly likely that the variables you are printing have trailing carriage returns. Try stripping these before printing. eg:

    $csvContent[0] =~ s/\r$//;

    etc.

      Thanks very much. It gets me closer, but only works on the lines with a group name. Stripping the same character from the line with the member info

      Result (with your suggestion):
      applegroup,
      applegroup,
      applegroup,
      applegroup,
      orangegroup,
      orangegroup,
      orangegroup,

      Thanks

Re: Strings overwrite themselves in print command
by AnomalousMonk (Archbishop) on Jun 27, 2016 at 22:35 UTC

    What hippo said. It's quite easy to exemplify this effect:

    c:\@Work\Perl>perl -wMstrict -le "my $overwrite = qq{AAAAA\rbbbb\rCCC\rdd\rE}; print $overwrite; " EdCbA

    Update: I would say the problem is likely not so much with leading or trailing carriage returns as with embedded  \r characters as in the example.


    Give a man a fish:  <%-{-{-{-<

Re: Strings overwrite themselves in print command
by BillKSmith (Monsignor) on Jun 28, 2016 at 03:34 UTC
    Logic is much simpler if you process logical records rather than lines and extract only the data that you need.
    use strict; use warnings; $/ = q(); while (my $record = <DATA>) { my @lines = split /\n/, $record; my $header = shift @lines; my ($grpNm) = $header =~ /\:\s*(\w+)/; foreach (@lines) { my ($memID) = unpack '@12A6'; print "$grpNm, $memID\n"; } } __DATA__ cn: applegroup member: CN=mem001,OU=Users,DC=myorg,DC=com member: CN=mem002,OU=Users,DC=myorg,DC=com member: CN=mem003,OU=Users,DC=myorg,DC=com member: CN=mem004,OU=Users,DC=myorg,DC=com cn: orangegroup member: CN=mem301,OU=Users,DC=myorg,DC=com member: CN=mem302,OU=Users,DC=myorg,DC=com member: CN=mem303,OU=Users,DC=myorg,DC=com

    OUTPUT,

    applegroup, mem001 applegroup, mem002 applegroup, mem003 applegroup, mem004 orangegroup, mem301 orangegroup, mem302 orangegroup, mem303
    Bill
      Bill,

      I like the simplicity in this approach. I haven't learned enough perl to come up with this myself so thanks for stretching my understanding. However, I am seeing an error when I apply this code:

      Not enough arguments for unpack at script.pl line 64, near "'@12A6';"

      Not certain what this means.

        It means your Perl is ancient and doesn't support the default second argument. Use
        my ($memID) = unpack '@12A6', $_;

        instead.

        Update: The change happened in 5.10 (2007), see Miscellaneous.

        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Strings overwrite themselves in print command
by Marshall (Canon) on Jun 28, 2016 at 05:37 UTC
    Your code confuses me. Here is one way to convert this into a .CSV format:
    #!/usr/bin/perl use warnings; use strict; while (my $line = <DATA>) { (my $group) = $line =~ /cn:\s+(\w+)/; process_record($group) if $group; } sub process_record { my $group = shift; my $line; while (defined ($line = <DATA>) and $line !~ /^\s*$/) { (my @columns) = $line =~ /=(\w+)/g; print join ',',($group,@columns); print "\n"; } } =example printout applegroup,mem001,Users,myorg,com applegroup,mem002,Users,myorg,com applegroup,mem003,Users,myorg,com applegroup,mem004,Users,myorg,com orangegroup,mem301,Users,myorg,com orangegroup,mem302,Users,myorg,com orangegroup,mem303,Users,myorg,com =cut __DATA__ cn: applegroup member: CN=mem001,OU=Users,DC=myorg,DC=com member: CN=mem002,OU=Users,DC=myorg,DC=com member: CN=mem003,OU=Users,DC=myorg,DC=com member: CN=mem004,OU=Users,DC=myorg,DC=com cn: orangegroup member: CN=mem301,OU=Users,DC=myorg,DC=com member: CN=mem302,OU=Users,DC=myorg,DC=com member: CN=mem303,OU=Users,DC=myorg,DC=com
    update: if you just need the "mem field", change print join ',',($group,@columns); to this
    print join ',',($group,(@columns)[0]);
Re: Strings overwrite themselves in print command
by tdsny71 (Initiate) on Jun 27, 2016 at 21:58 UTC

    By the way, the variables do yield the correct values independently

    e.g.

    $grpNM = "applegroup"
    $memID = "mem001"

    Thank you.