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

I am trying to call a subroutine in a loop, but its exiting after executing the sub only once. Any idea why? Or can someone point me to a similar question posted before in this forum?

the array corners contains: @corners= AAA BBB CCC DDD

and my code is :
while(<CORNERS_LIST>){ $_=~ s/\s+/ / ; chop $_; push @corners, $_ ; print "\n@corners\n"; } my $corner; foreach(@corners){ $corner=$_; &loading_tsc; } sub loading_tsc{ chdir($corner) or die "\n $!\n"; print "\n"; print `pwd`; print "\n"; }

But the result I am getting is :

/file/path/is/AAA No such file or directory

The desired result I wanted to see is

/file/path/is/AAA /file/path/is/BBB /file/path/is/CCC /file/path/is/DDD

Replies are listed 'Best First'.
Re: calling subroutine inside loop - ERROR - subroutine executes only once
by Discipulus (Canon) on Dec 24, 2014 at 08:19 UTC
    hello kaushik9918 and welcome.

    Your code is full of strange constructs and even if i'm not a master, i can suggest you some more perlish Perl.

    First a slightly modified version of your code:
    use strict; use warnings; my @corners; $|++; #get correct order of print and die (STDOUT STDERR) while(<DATA>){ $_=~ s/\s+/ / ; chop $_; push @corners, $_ ; print "\n@corners\n"; } my $corner; foreach(@corners){ $corner=$_; &loading_tsc; } sub loading_tsc{ print "DEBUG: loading_tsc received '@_'"; chdir($corner) or die "\n $!\n"; print "\n"; print `pwd`; print "\n"; } __DATA__ AAA BBB CCC DDD
    with this code the output is:
    AAA AAA BBB AAA BBB CCC AAA BBB CCC DDD DEBUG: loading_tsc received '' No such file or directory
    Firstly onother way to get array filled with lines from a file:
    @corners = <DATA> ;

    then declare your var within the loop without juggling with $_:
    foreach my $corner(@corners){...


    More on when you call your subroutine you pass no argguments to it but you modify a global variable inside it. is not the safer way:

    foreach my $corner(@corners){ chomp $corner; # we still need to chomp it.. &loading_tsc ($corner); # better use of a sub. }


    Now the chdir-path part: when you deal with path is better have an absolute one to use. In fact assuming you run your original code frome the dir /var/tests you get, as the first item of the array is processed, chdir AAA and if it is succesful you now are in /var/tests/AAA in the next iteration you try to go in /var/tests/AAA/BBB while you probably want /var/tests/BBB.

    Better would be to record the starting directory using the core Cwd module and concatenate the path using this base, as in:
    use Cwd; my $start_dir = getcwd; ... sub loading_tsc{ print "DEBUG: loading_tsc received '@_'"; my $current_corner = shift; chdir($start_dir.'/'.$current_corner ) or die "\n $!\n"; print "\n"; print `pwd`; print "\n"; }

    This probably works as you wanted, but is still no safe Perl: when dealing with paths you need to be sure to the right thing possibly for every OS you can encounter. And concatenate paths with '/' can also be annoying. The core File::Spec is handy in this case:
    use File::Spec; .. my $current_dir = File::Spec->rel2abs('.'); .. #in the sub now you can do: my $path_to_go = File::Spec->catdir( $current_dir , $current_corner ); chdir $path_to_go or die "unable to chdir in $path_to_go\n";


    You type some chars more but you can be sure to do the right thing and have a more robust code.

    HtH
    L*
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      Thanks
Re: calling subroutine inside loop - ERROR - subroutine executes only once
by LanX (Saint) on Dec 24, 2014 at 11:41 UTC
    This line dies at the second loop

    chdir($corner) or die "\n $!\n"

    And it tells you why, it couldn't find the path.

    No such file or directory

    You are trying to descend successively into /file/path/is/AAA/BBB/CCC/DDD but BBB is on the same level like AAA not deeper!

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

Re: calling subroutine inside loop - ERROR - subroutine executes only once
by Laurent_R (Canon) on Dec 24, 2014 at 18:42 UTC
    Hi, LanX has given you the reason why your code failed. You might have found out by yourself with more ease if you had used a more meaningful error message. Instead of:
    chdir($corner) or die "\n $!\n";
    You may want something like this:
    chdir($corner) or die "\nCannot cd to $corner $!";
    giving you more useful information on what failed. BTW, it is better not to put "\n" after $!, because you get more information if you don't. Consider these two one-liners:
    $ perl -e 'my $c = "foobar.txt"; open my $FH, "<", $c or die "cannot +open $c $!"; ' cannot open foobar.txt No such file or directory at -e line 1. $ perl -e 'my $c = "foobar.txt"; open my $FH, "<", $c or die "cannot +open $c $!\n"; ' cannot open foobar.txt No such file or directory
    As you can see, without the "\n", you get the code line number where the exception occurred (of course, this is not very useful in a one-liner, but quite practical with larger programs).

    A small additional point is that the:

    &loading_tsc;
    syntax for calling a function has been superseded about 20 years ago and was replaced with:
    loading_tsc(); # or: loading_tsc($param1, $param2);
    The syntax with & may still be used, but only to obtain some special effects on the function call (by-passing prototypes). You are not using prototypes here (and they would not be very useful), so rather use the regular syntax with parens.
      Thanks guys - I could get it to work . Was out for sometime, and just checked on your replies now. thanks again