views:

151

answers:

3

This is a beginner-best-practice question in perl. I'm new to this language. The question is:

If I want to process the output lines from a program, how can I format THE FIRST LINE in a special way?

I think of two possibilities:

1) A flag variable, once the loop is executed first time is set. But it will be evaluated for each cycle. BAD solution

2) An index-based loop (like a "for"). Then I would start the loop in i=1. This solution is far better. The problem is HOW CAN I DO IT?

I just found the code for looping over with the while ( <> ) construct.

Here you can see better:

$command_string = "par-format 70j p0 s0 < " . $ARGV[0] . "|\n";                                                                                

open DATA, $command_string  or die "Couldn't execute program: $!";

print "\t    <div>&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;|-- <strong>Description</strong></div>\n";
while ( defined( my $line = <DATA> )  ) {
   chomp($line);
   # print "$line\n";
   print "\t    <div>&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;&‎nbsp;|&‎nbsp;&‎nbsp;&‎nbsp;-- " . $line  . "</div>\n";
}

close DATA;

Please also don't hesitate in correcting any code in here, this is my first perl poem.

Thanks!

+5  A: 

To handle the first line differently, you could just put

$line = <DATA>;

above your loop.

With proper checking for read problems (empty file, etc.) this should be

if ($line = <DATA>) {
    ...do special things...
}

while (my $line = <DATA>) {
    ...do regular things...
}

I'm not sure about the defined() call. You might not need it, since an empty string has a false truth value.

fmarc
The defined() call is unnecessary - see "man perlop" - Perl adds it implicitly when you do while(<fh>)
Alnitak
You need the defined call in the if, but not in the while, whiles have a bit of magic that tests for definedness instead of truth when the function is readline (aka <>), glob (also aka <>), or readdir.
Chas. Owens
+7  A: 

You can always use $. or the English name $INPUT_LINE_NUMBER to control the logic in your loop with:

while (my $line = <>) {
    if ($. == 1) {
        # do cool stuff here
    }
    # do normal stuff here
}
D.Shawley
yep, that's the first approach. I prefer the second, but this is a fix for the problem. THanks!
alvatar
I guess if this is so voted is because is better approach, isn't it?
alvatar
hum... but although the TIE solution doesn't work, it has the very good quality of leting me access arbitrary lines. How could I do that in this way? The conditions can become too complicated if a have changes in several lines.
alvatar
+4  A: 

From a 'best practices' perspective there is much wrong with that code sample:

open DATA, $command_string  or die "Couldn't execute program: $!";
  • Security hole, please exploit me.
  • DATA is a magical value that points to a __DATA__ section at the end of the current file.
  • You should use

    open my $fh
    

    Which uses a lexical variable for a file handle instead of a global.

  • You should use 3 arg open, ie:

    open my $fh, '<'  , $filename
    open my $fh, '-|' , $command
    open my $fh, '-|' , $command, @args
    

    sadly I have yet to work out how 3-arg works with dual-pipes. theres' this IPC::Open2 thing, but I haven't worked out how to use that effectively yet. Suggestions welcome .

Kent Fredric
This proves that copy-pasting code from internet is a dangerous practice. Thanks for your answer.
alvatar