Well, they jest don't work me all that hard here at my happy company, so when a coworker approached and asked if I could write him a quick script to format the output of bdf so he could import it into Excel, I said "Abso-positively, homedude! I've got 8 hours to kill!"

So what's this bdf thing? Read the man page for more details. All I knew was that he tried to capture the output from the screen and paste it into Excel, but the formatting was just ALL wrong. He gave me a sample of the normal screen output from bdf.

Filesystem kbytes used avail %used Mounted on /dev/vg00/lvol3 143360 45210 92038 33% / /dev/vg00/lvol1 83733 29494 45865 39% /stand /dev/vg00/lvol8 2048000 820619 1150910 42% /var
and also a sample of the fnarky output.
Filesystem kbytes used avail %used Mounted on i47ebfl2:/mnt/home2 51249152 34195824 16920184 67% /nfs/home2 i47ebfl1:/mnt/home1 51249152 27468376 23595000 54% /nfs/home1 i47ebfl1:/mnt/home 262144 1496 244640 1% /nfs/home
I wanted to do it in a one-liner originally, so I could impress "Joe" with my Perl knowledge. Unfortunately, I haven't had occasion to use all the marvelous tools such as map and grep and so on. I decided just to try and get something that functioned first. So I pulled out my dusty Camel 2 and started coding.

It took me a while -- I started with about 16 or 18 lines, and there was an annoying little bug which resulted in some empty cells in the final CSV output. I fixed said bug with a grep on /./. What follows was my proud presentation to the occupants of #perlmonks, without the newlines or comments.

# pipe output from bdf through this script for a surprise @lines = <>; { if (scalar(@tokens = split /\s+/, (shift @lines)) > 1) { } else { push @tokens, (grep /./, (split /\s+/, (shift @lines))); } push @csv, ((join ',', @tokens) . "\n"); redo if @lines; } print @csv;
Doh! Thanks zdog, I COULD have done (scalar...) || (push...). Quoth zdog, "I picked it up reading 'jcwren code'". Excellent. Let's put it on one line.
@lines = <>; { (scalar(@tokens = split /\s+/, (shift @lines)) > 1) || +push @tokens, (grep /./, (split /\s+/, (shift @lines))); push @csv, ( +(join ',', @tokens) . "\n"); redo if @lines; } print @csv;
Well this works fine. So I send it to "Joe", and his eyes get wide and I just grin and say "It works. Try it." I caution him that it doesn't work if there are spaces in the names of the filesystems. It's not really robust, but then, he didn't give me a lot of data. So Joe is satisfied. But I'm not, and I've got three hours before I can leave.

So the next step is to clean out the parens and the unnecessary functions. Like scalar. Don't even remember why I used scalar. Insurance I guess. And then there is substituting "or" for || so I can get rid of some more parens.

@lines = <>; { (@tokens = split /\s+/, shift @lines) > 1 or push @toke +ns, grep /./, split /\s+/, shift @lines; push @csv, (join ',', @token +s) . "\n"; redo if @lines; } print @csv;
This is great! The marginal value to my company of these code improvements is actually negative, and falling rapidly. The final task is to take some hints from posts by japhy. I use odd delimiters for quoting. I get rid of whitespace. I use one-letter variable names. The final version, which is as far as I can take it, is as follows:
@i=<>;{(@w=split /\s+/,shift @i)>1 or push @w,grep /./,split /\s+/,shi +ft @i; push @c,(join q;,;,@w).qq.\n.;redo if @i;}print @c
which gave the desired output
/dev/vg01/lvol2,8257536,158029,7593289,2%,/mnt/ims_logs /dev/vg01/lvol1,16384000,13542344,2755462,83%,/mnt/ims i47ebfl2:/mnt/home2,51249152,34196640,16919376,67%,/nfs/home2 i47ebfl1:/mnt/home1,51249152,27468600,23594776,54%,/nfs/home1
In summary, this was a throwaway script. I would never intentionally obfuscate any code that someone would have to come along and maintain later. This was the first occasion I've ever had to do a little obfuscation, but I would never have tried to do it if it weren't for one original design factor. Namely, the fact that using a block with redo was (in this case) better than using the usual for or foreach. Said block confused a fellow programmer for a bit.

So now I've had my first taste of obfuscation. Honestly? It was a so-so experience. I taught myself some new constructs, with the help of zdog, jlp, h0mee, and also jcwren and japhy. But I think I like solving useful problems a lot better, and will stick with functional (non-JAPH) readable scripts for the time being.


So go ahead -- what would you have done differently? How? Why?

e-mail neshura


In reply to Evolution of an Obfuscated Throwaway Script by neshura

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.