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


for ($i=0;$i<=$#steps;$i++) { open MIN_RUN, ">run"; print MIN_RUN qq(/opt/sander -i $steps[$i].min -p ../$steps[$i].pr +mtop -o $step[$i]$step[$i].e &\n); print MIN_RUN qq(/opt/sander -i $steps[$i].min -p ../../$steps[$i- +1]/$step[$i-1].prmtop -o $step[$i]$step[$i-1].e &\n); }

here is what is printed out in file run:
/opt/sander -i ele0.5.min -p ../ele0.5.prmtop -o .e &
/opt/sander -i ele0.5.min -p ../../ele1.0/.prmtop -o .e &

I got the error msg in these two "print" lines.

The correct "run" file is supposed to look like this:
/opt/sander -i ele0.5.min -p ../ele0.5.prmtop -o ele0.5ele0.5.e
/opt/sander -i ele0.5.min -p ../../ele1.0/ele1.0.prmtop -o ele0.5ele1.0.e &

So what is going on here?

Replies are listed 'Best First'.
Re: Use of uninitialized value in concatenation (.) or string
by jwkrahn (Abbot) on Aug 23, 2009 at 04:32 UTC

    Enable the warnings and strict pragmas and perl will tell you (that the array @step is not declared.)

Re: Use of uninitialized value in concatenation (.) or string
by bichonfrise74 (Vicar) on Aug 23, 2009 at 06:19 UTC
    $step should be $steps. As jwkrahn pointed out, if you enabled the warnings and strict pragmas, then you would have seen this error.

    Also, please see how to use open with 3 arguments properly. And you should add 'or die ... ' on your 'open' line so that you know that there are errors when your script cannot open the file properly.
Re: Use of uninitialized value in concatenation (.) or string
by Util (Priest) on Aug 23, 2009 at 17:46 UTC

    ++jwkrahn and ++bichonfrise74.

    Two other errors are lurking in the code.

    1. You are overwriting the run file on each loop. You probably just need to move the open to just before the loop.
    2. You are looping over for ($i=0;$i<=$#steps;$i++), ( which is better written as foreach my $i ( 0 .. $#steps ) ), but inside the loop you refer to $steps[$i-1]. On the first loop through, $i is 0, so $i-1 is -1, and $steps[-1] will give you the *last* element in the array. If that is what you meant to do, then fine. If not, then perhaps you need to start the loop index at 1 instead of 0?

    Working, tested code:

    #!/usr/bin/perl use strict; use warnings; my @steps = ( 'ele1.0', 'ele0.5' ); die if @steps < 2; open my $MIN_RUN, '>', 'run' or die "Cannot open 'run': $!"; my $last_step = $steps[0]; for my $step ( @steps[1..$#steps] ) { print $MIN_RUN "/opt/sander -i $step.min -p ../$step.prmtop -o $st +ep$step.e &\n"; print $MIN_RUN "/opt/sander -i $step.min -p ../../$last_step/$last +_step.prmtop -o $step$last_step.e &\n"; $last_step = $step; } close $MIN_RUN or warn;
    Output:
    /opt/sander -i ele0.5.min -p ../ele0.5.prmtop -o ele0.5ele0.5.e & /opt/sander -i ele0.5.min -p ../../ele1.0/ele1.0.prmtop -o ele0.5e +le1.0.e &

      After adding use strict and correcting all the typos (steps), I got this error:
      Global symbol "@steps" requires explicit package name.
      What does "use strict" do and in this case should I make @steps local?

        Use my in the proper scope to create the @steps variable.

        use strict; is a pragma that enforces lexical scoping of variables. With some very unusual exceptions, this is just a "compile time" deal. There are "our" vars (package scope) and "local" vars. Use strict and my $vars until you are very sure about why you should use one of these other forms.

        Something like this is almost always wrong in Perl (almost always doesn't mean always, it just means almost:

        for ($i=0;$i<=$#steps;$i++){}
        my @steps = (..list of some stuff.....); foreach my $step (@steps) { ..use $step...here... no $i index needed.. }