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

I feel somewhat dumb asking this question. I've played around with this for a while, and read perldoc(s), but the answer is aluding me.

My snippet of code looks like:

use strict; use warnings; my $infile = shift; open(INIFILE, "$inifile"); while (<INIFILE>) { (my $server, my $dir, my $type) = split if !/^#/; print "$server $dir $type\n"; } close(INIFILE);

and my data in INIFILE looks like:

# commments # more comments # yadda yadda fooserver foodir footype fooserver2 foodir2 footype2

This works, except that I get several blank lines as output before the real data -- it must be parsing split for the lines starting with #. Why?

I tried print if !/^#/; instead and it worked as expected...

Thanks, --ibanix


<-> In general, we find that those who disparage a given operating system, language, or philosophy have never had to use it in practice. <->

Replies are listed 'Best First'.
Re: Context of "if" statements?
by pg (Canon) on Nov 24, 2002 at 03:44 UTC
    The problem IS with the next line. As the split has been skipped, $server, $dir, $type, all three of them are undef, and in the print statement, you are trying to concatenate undef's. This is easy to prove, it will be fine, if you change your print statement to:
    print "$server $dir $type\n" if defined($server);
    So just put those two lines into one if block.
      Thank you sir! I now understand.

      <-> In general, we find that those who disparage a given operating system, language, or philosophy have never had to use it in practice. <->
Re: Context of "if" statements?
by tadman (Prior) on Nov 24, 2002 at 03:13 UTC
    You're not skipping the lines, that's why. You always assign and print regardless. What about this:
    while (<INFILE>) { next if /^#/; my ($infile, $dir, $type) = split; print "$infile $dir $type\n"; }
    A few refinements can be made if you don't care about what you're printing:
    while (<INFILE>) { next if /^#/; my @split = (split)[0..2]; print "@split\n"; }
    Use next to idiomatically skip to the next valid line.

    You are probably getting warnings too. You've used $infile and $inifile where I think you mean only one of the two.
      You are correct, $infile is a typo.

      Is still do not understand why
      (my $server, my $dir, my $type) = split if !/^#/
      does not work (that is, it splits every line), and
      print if !/^#/
      does work (it only prints lines not starting with #).

      What's the difference?

      <-> In general, we find that those who disparage a given operating system, language, or philosophy have never had to use it in practice. <->
        Having my in the same context as a trailing if is usually bad form. As far as I can tell, the variables are declared regardless of the outcome of the if and are scoped to the block.

        In plain english, this means that the split is not occuring, but the variables are there, and you are still printing because there is no conditional on the print.

        That's why I suggested using a next call to skip to the next line. If it is a comment, there's no point in calling either split or print, is there?

        Update:
        For additional clarity, here's an example of what's happening:
        while (<INFILE>) { my ($infile, $dir, $type); if (!/^#/) { ($infile, $dir, $type) = split; } print "$infile $dir $type\n"; }