Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Reformat command output inline

by RenMcCourtey (Acolyte)
on Jun 29, 2016 at 12:54 UTC ( [id://1166879]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, I'd like to seek your help on tedious task I'm fighting today. I need to reformat ldapsearch output to acceptable form, and I'd prefer to do that inline with one command. Originally I had complex piped steps of sed and grep and then I realized perl could do that better but I don't know how. Basically I'd like to drop empty or ^dn: lines and merge some other lines together while trimming them. Source looks like this:

dn: distinguished_name1 cn: common_name1 orclnetdescstring: complex_address_line1 dn: distinguished_name2 cn: common_name2 orclnetdescstring: complex_address_line2 dn: distinguished_name3 cn: common_name3 orclnetdescstring: complex_address_line3
And the result should go like this:
common_name1=complex_address_line1 common_name2=complex_address_line2 common_name3=complex_address_line3
Now I believed this one liner, which I completed with help here would do that: perl -p0e 's/\n^$|\n^dn:*$//mg','s/cn: //g','s/\norclnetdescstring: /=/g' nejms.txt but it doesn't. And as it's getting more complex, I can't see the errors and maybe I'd be better with original sequence of more generic commands, I'm not sure.

Replies are listed 'Best First'.
Re: Reformat command output inline
by haukex (Archbishop) on Jun 29, 2016 at 13:13 UTC

    Hi RenMcCourtey,

    While what you want to do could be done with a oneliner*, as the code gets more complex it's certainly advisable to use the proper tools for the job.

    Apparently ldapsearch outputs in LDIF format, which can be read by, for example, Net::LDAP::LDIF. Here's a quick example I whipped up using the documentation, its output looks like what you want:

    use Net::LDAP::LDIF; my $ldif = Net::LDAP::LDIF->new('nejms.txt', 'r', onerror=>'die'); while (!$ldif->eof) { my $entry = $ldif->read_entry; print $entry->get_value('cn'), "=", $entry->get_value('orclnetdescstring'), "\n"; } $ldif->done;

    If it's an option for you, you could maybe use Net::LDAP for all your work. (Disclaimer: I don't have experience with the module. It does have a long release history and good reviews, though.)

    * I'd strongly recommend the above instead, this is just an example of one way to do it:

    $ perl -ne 'next if /^dn:|^\s*$/; s/^cn:\s*(.+)\n/$1/; s/^orclnetdescstring:\s*/=/; print' nejms.txt common_name1=complex_address_line1 common_name2=complex_address_line2 common_name3=complex_address_line3

    Hope this helps,
    -- Hauke D

      Thanks a lot for both examples. This is actually what I had on mind in a broader sense, like, if I don't scratch my left ear with my right hand, so to speak. Clearly I did.:-) I'll dig deeper into links you posted now.
Re: Reformat command output inline
by choroba (Cardinal) on Jun 29, 2016 at 13:04 UTC
    Just a small fix needed:
    perl -p0e 's/\n^$|^dn:.*\n//mg; s/cn: //g; s/\norclnetdescstring: /=/g +'

    Main problems:

    Newline removed after, not before | | | | v v 's/\n^$|\n^dn:*$//mg','s/cn: //g','s/\norclnetdescstring: /=/g' 's/\n^$|^dn:.*\n//mg; s/cn: //g; s/\norclnetdescstring: /=/g ^ ^ | | Missing | dot Optional: no need to switch between Perl and shell +, using semicolons instead of commas.
    ($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,
      Thank you, this not only does what I need but also helps me understand syntax better. Just one more question, if you don't mind. I understand why newline should be at the end of the dn: line now (e.g. first line) but why empty line also can't be like that?
        It can, i.e. you can start the regex with s/^\n| , but it doesn't change the output. Moving the newline to the end for the dn: line was essential to make it work for the first record.

        ($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: Reformat command output inline
by kcott (Archbishop) on Jun 30, 2016 at 02:33 UTC

    G'day RenMcCourtey,

    As a more general solution to those already provided, when confronted with blocks of data that are to be processed as a single unit, read each block as a single record by localising $/, the input record separator. (See "perlsub: Temporary Values via local()" and "perlvar: Variables related to filehandles".)

    Here's how you might do this with your posted data and requested output format:

    #!/usr/bin/env perl -l use strict; use warnings; { local $/ = "\ndn: "; while (<DATA>) { / ^ cn: \s+ (.*?) $ .*? ^ orclnetdescstring: \s+ (.*?) $ /msx; print join '=', $1, $2; } } __DATA__ dn: distinguished_name1 cn: common_name1 orclnetdescstring: complex_address_line1 dn: distinguished_name2 cn: common_name2 orclnetdescstring: complex_address_line2 dn: distinguished_name3 cn: common_name3 orclnetdescstring: complex_address_line3

    Output:

    common_name1=complex_address_line1 common_name2=complex_address_line2 common_name3=complex_address_line3

    — Ken

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1166879]
Approved by Athanasius
Front-paged by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (8)
As of 2024-03-28 09:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found