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


Dear and Serene Monks

I would like to know if there's a possibilty of confusion between the two "$_" in my program (each $_ correponds to a line of a input file (there are two input files for my code)

My code seems to work but I would like be 100 % sure it's OK

Here is my code

#!/usr/bin/perl use strict; use warnings; use diagnostics; # la commade "use strict" permet d'être plus rigoureux ############################################## # TASKS MADE BY THE SCRIPT ############################################## # the task of this script is to look for the following aircraft_id ################################## ## ARGUMENTS OF THE SCRIPT ################################## ##################################### # do not forget the $ before the ARGV ##################################### # THE FIRST ARGUMENT : # we have to give the name of the regulation which will help us to ope +n the first file # the name of the first file to open is : Regulation_Slot_List_${reg_ +id} my ${reg_id} = "$ARGV[0]"; # THE SECOND ARGUMENT # it will be used later to open the ALL_FT file my $date = "$ARGV[1]"; ################# END OF THE DECLARATION OF THE ARGUMENTS ################# IN WHICH DIRECTORY WE ARE ######################## my $Current_Dir = `pwd`; print STDOUT "the current directory is $Current_Dir"; ##################################################################### ################### OPEN THE ANALYSIS INFILE ######################### +### # open the first file # do not forget the "" to declare my ${analysis_file} = my ${analysis_file} = "without_commas_Analysis_Regulation_Slot_List_${ +reg_id}_last.csv"; open(INFILE,"<${analysis_file}") or die "Can't open ${analysis_file} : + $!"; ###################################################################### +##### ################### OPEN THE OUTFILE ############################ # open the first file # do not forget the "" to declare my ${analysis_file} = my $outfile = "with_ALL_FT_${analysis_file}"; open(OUTFILE,">${outfile}") or die "Can't open ${outfile} : $!"; ###################################################################### +##### # we want to skip the first line of the INFILE while (<INFILE>){ # the /^ indicates the begining of the research for $_ ($_ is unde +rstated here) my @Elements = split(/;/,$_); # $Elements[2] is the $CTO my $aircraft_id = $Elements[1]; if ($Elements[4] ne ""){ # print STDOUT "$Elements[4]"; ################### OPEN THE ALL_FT FILE ##################### +####### # open the first file # do not forget the "" to declare my ${ALL_FT_file} = my ${ALL_FT_file} = "ALL_FT.${date}"; open(INFILE_2,"<${ALL_FT_file}") or die "Can't open ${ALL_FT_f +ile} : $!"; ############################################################## +############# while(<INFILE_2>){ my $Line_ALL_FT = $_; print STDOUT "$Line_ALL_FT\n"; my @Parts_ALL_FT = split(/;/,$Line_ALL_FT); my $aircraft_ALL_FT_id = $Parts_ALL_FT[2]; # print STDOUT "le nom de l'avion dans le fichier ALL_FT e +st $aircraft_ALL_FT_id\n"; # print STDOUT "le nom de l'avion dans le fichier analysis + est $aircraft_id\n"; next if ($aircraft_id ne $aircraft_ALL_FT_id); if ($aircraft_id eq $aircraft_ALL_FT_id){ # do not forget the "" in the declaration of the OUTFI +LE print OUTFILE "$aircraft_id\n"; } } close INFILE_2; } } close INFILE; close OUTFILE;


Here is my first input file : the analysis file (the true one, the one I opened with wordpad)
08:47:46;;;;; 08:48:45;;;;; 08:49:43;DAL11;08:47;527;08:50;530;3 08:50:41;;;;; 08:51:40;;;;; 12:16:28;RYR211;12:13;733;12:16;736;3 12:17:26;EEZ95A;12:23;743;12:17;737;-6 12:18:24;SHT2938;12:24;744;12:17;737;-7

Here is my second input file : the ALL_FT file
LIRF;KJFK;EEZ95A; EGKK;KATL;DAL11; ENCN;EHAM;KLM1210; LEMD;LIMC;AZA067;

Here is my output file
DAL11 EEZ95A

Replies are listed 'Best First'.
Re: risk of confusion
by shmem (Chancellor) on Aug 07, 2007 at 16:07 UTC
    So the relevant parts of your code are, along with the question:
    my $analysis_file = shift; open INFILE_1, '<', $analysis_file or die "Can't open '$analysis_file': $!\n"; while(<INFILE_1>) { my $ALL_FT_FILE = $_; # or some part of $_ after munging open INFILE_2, '<', $ALL_FT_FILE or die "Can't open '$ALL_FT_FILE': $!\n"; while(<INFILE_2>) { ... # is the outer $_ clobbered here? } }

    That's considerably shorter, and more to the point, isn't it?

    Answer: No, each $_ is localized to its own while() block. But you can't access the contents of the outer $_ from the inner block, unless you assign that to another variable.

    <update>

    *Sigh*. As jdporter pointed out, yes, $_ isn't localized in a while loop:

    open O, '>', 'foo'; print O "bar\n"; close O; open O, '>', 'bar'; print O "$_\n" for qw(foo quux wrdlbrmfd); close O; open I, '<', 'foo'; while (<I>) { chop; open II, '<', $_ if -f $_; while (<II>) { print; } print "\$_ = '$_'\n"; } __END__ foo quux wrdlbrmfd $_ = ''

    As you see at the last line of the ouput above, $_ is clobbered.

    </update>

    Some nits:

    • three argument open is generally preferred (there are edge cases where 2-argument open makes sense)
    • the construct "${ALL_FT_FILE}"is only used to disambiguate an interpolated variable from an adjacent literal, as in "${foo}_bar"; interpolating a single variable in a double quoted string is bad practice, unless it is necessary - in your code it is not
    • code inside a block is better readable if it's indented relative to its enclosing brackets

    </pedantic> :)

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      each $_ is localized to its own while() block.

      I'm sorry, that is false. Are you getting while confused with foreach?

      As it says in When to Still Use local():

      it's important to localize $_ in any routine that assigns to it. Look out for implicit assignments in while conditionals.
      So the correct answer to the OP is actually Yes, there will be "confusion". local can be used to remedy the problem.

      A word spoken in Mind will reach its own level, in the objective world, by its own weight
        Are you getting while confused with foreach?

        Obviously. Thanks for the correction. I'm very sorry about having propagated crap *blush*... maybe the corrections do mend that.

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: risk of confusion
by thezip (Vicar) on Aug 07, 2007 at 16:04 UTC

    steph_bow,

    If you're concerned that that the $_ variable is going to get clobbered, try reading/assigning each line into a variable, as in:

    while (my $file_1_line = <INFILE>) { ... do stuff }

    BTW, your code would be much more readable (to Perlmonks) if you only included the relevant code that demonstrates your particular issue. You might consider weeding it down to about 10-15 lines, with not so many comments, as they don't aid in increasing my understanding of the problem at hand.

    Update: Added a number to the variable name


    Where do you want *them* to go today?