Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Convert from awk to perl

by darthtux (Initiate)
on Jul 19, 2008 at 05:31 UTC ( #698773=perlquestion: print w/replies, xml ) Need Help??
darthtux has asked for the wisdom of the Perl Monks concerning the following question:

I have a shell script with that uses the following awk section that I would like to put into perl.

Basically it takes a sar file, sa17, and gets information on the network section and formats the time which is in 10 minute intervals. The time is set to exactly 10 minutes because this section is part of a larger script which gets other information from sar and the mysql database and concatenates it all together by the time.

Any guidance would be greatly appreciated.

sar -n DEV -f sa17|awk -v mydate="2008-02-17" '

    BEGIN {lastdate=99}

        if ( substr($3,1,3) == "eth" ) process=1
        if ( substr($3,1,3) == "bon" ) process=1
        if ( $3 == "eth0" ) process=1
        if ( ! ( $2 == "AM" || $2 == "PM" ) ) process=0
        if ( $3 == "IFACE" ) process=0
        if ( process == 0 ) next
            if ( lastdate != currentdate && lastdate != 99 ) 
                print datehradj":"datemmadj":"datessadj" "myeth0" "myeth1 >> "sarnetwork"
        if ( $3 == "eth0" )  myeth0=$6
        if ( $3 == "eth0" )  myeth1=$7
        if ( $2 == "AM" && filehour == 12 ) filehour="00"
        if ( $2 == "PM" && filehour < 12 ) filehour=filehour+12
        dateadj=(int(( filedaysecs + 300 ) / 600) * 600)
        datehradj=int(((int(( filedaysecs + 300 ) / 600) * 600)) / 3600 )
        datemmadj=int((((int(( filedaysecs + 300 ) / 600) * 600)) % 3600 ) / 60 )
        if ( datehradj == 0 ) datehradj="00"
        if ( length(datehradj) == 1 ) datehradj="0"datehradj
        if ( datemmadj == 0 ) datemmadj="00"

    END {
        print datehradj":"datemmadj":"datessadj" "myeth0" "myeth1 >> "sarnetwork"

Replies are listed 'Best First'.
Re: Convert from awk to perl
by pc88mxer (Vicar) on Jul 19, 2008 at 06:59 UTC
    Have you tried the a2p program that comes with perl?
Re: Convert from awk to perl
by RMGir (Prior) on Jul 19, 2008 at 10:57 UTC
    I second the recommendation: start by trying a2p.

    But if that doesn't work, you're in luck - perl and awk are very similar.

    First, save a few outputs from sar, so you can test your script. Run those sar outputs thru your awk script (removing >> "sarnetwork" so you get the output on the console) so you know what your perl script should generate.

    The next thing you need to do to accent those similarities is use the -a and -ne switches to perl. -a makes perl "autosplit" its input the same way awk does, and -ne makes perl run the command line expression you're about to pass for every line of input, the same way awk does.

    The next thing to remember is that while awk splits its input line into $1, $2, $3, thru $NF, perl splits it into $F[0], $F[1], ... $F[$#F] (when using the -a switch). Note that indexes in awk are 1-based, but perls are 0-based, so $1 becomes $F[0].

    Once you've replaced all the $[0-9] variables with their $F[] equivalents, you need to add a $ in front of all your variables, since that's how perl refers to scalars. You also need to terminate your statements with semicolons.



    In perl, substr indexes are 0-based, so you'll need to subtract 1 from all the arguments to substr.

    Perl makes building up strings simpler via something called interpolation, so

    print datehradr":"datemmadjr...
    # perl's print doesn't add in the \n for you print "$datehradr:$datemmadjr...\n"

    Finally, it isn't QUITE so easy in perl to append to a file, but you can let the shell do that for you by putting the >> sarnetwork after the whole command.

    So here's some COMPLETELY untested code for you to try. You should actually take everything between "perl" and ">>" and move it into a separate script, to simplify testing. But here's the whole command line:

    Edit: Added the eq and if brace fixes from philipbailey and Anonymous Monk below, thanks!

      That won't quite work--braces, {}, are always required for blocks in Perl. So, for instance, the first "if" statement would need to be written as:
      if ( substr($F[2],0,3) eq "eth" ) { $process=1; }
      Update: Or to be a bit more "Perlish" you could write:
      $process=1 if (substr($F[2],0,3) eq "eth");
      Update 2: Correction of string comparisons, as per Anonymous Monk.
        strings are compared with eq, numbers with ==
Re: Convert from awk to perl
by oko1 (Deacon) on Jul 19, 2008 at 20:39 UTC
    I have a shell script with that uses the following awk section that I would like to put into perl.

    I'm going to run counter to what others here have said by telling you that 'a2p' will not do that. It may well produce some Perl code that will imitate what you were doing with 'awk' - but you'll gain nothing in terms of knowledge, speed, maintainability, readability, or anything else I can think of. (Do feel free to skip the rest of this rant "Meditation in the Wild" if you were just doing this for some sort of Perl usage coolness points or on a bet or something like that.)

    If, on the other hand, you actually wanted to learn some Perl by rewriting this - that's something that I'd see as a valuable goal. Perl has a much more comprehensive toolbox than 'awk' does, so if you had been trying to chop down a tree with an 'awk' jacknife, you could use a Perl jacknife, too... but you'd be much, much better off with the Perl chainsaw. Or Perl dynamite. Or a Perl Caterpillar D9.

    As an example, the validation routine that you have at the top of your script would benefit from rethinking (as well as rewriting in Perl) quite well.

    # Original 'awk' code { process=0 if ( substr($3,1,3) == "eth" ) process=1 if ( substr($3,1,3) == "bon" ) process=1 if ( $3 == "eth0" ) process=1 if ( ! ( $2 == "AM" || $2 == "PM" ) ) process=0 if ( $3 == "IFACE" ) process=0 if ( process == 0 ) next [...]

    Since Perl does not automatically loop over the input file (but do see 'perldoc perlrun' for the '-n' switch) or split the input into fields (but see 'perldoc perlrun' for the '-a' switch), we'll need to do those explicitly. After that, though, things get to be fun. :)

    # Perl version while (<>){ # Loop over the input file/stream my @line = split; # Split each line into "fields" next unless $line[1] =~ /^[AP]M$/ && $line[2] =~ /^(eth|bon)/; # Note: the 'eth0' and the 'IFACE' line aren't in here because the +y don't # contribute anything to the validation routine as originally writ +ten. [ ... ]

    That was it; essentially, that whole routine became just one line. The rest of the script can be rewritten in much the same way, with as much or more benefit in clarity, readability, etc.

    My point, overall, is that some scripts - particularly simple ones like this, and especially if you've already found the motivation to do so - should be rewritten every once so often, whether in other languages or in the original one. At the very least, this will show you if you've learned anything about those languages in the meantime - or let you learn something new by doing a task you already understand in a different way.

    If you decide to do that, feel free to come back here and ask for help. This is, in my experience, one of the friendliest forums out there when it comes to helping a struggling Perl neophyte - at least if you can show what you've coded so far. Give it a shot!

    Human history becomes more and more a race between education and catastrophe. -- HG Wells

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://698773]
Approved by planetscape
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (5)
As of 2018-04-20 19:12 GMT
Find Nodes?
    Voting Booth?