Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

File::Find and $_ in the wanted sub

by Anonymous Monk
on Jun 04, 2010 at 19:57 UTC ( #843194=perlquestion: print w/replies, xml ) Need Help??

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

Hiya Monks, I thought I understood subroutines until I needed to use File::Find. I can make it do what I want, but I'm disturbed because I don't understand how the subroutine used as its first parameter gets $_. For example:
#!/usr/bin/perl use File::Find; find (\&testy, "."); sub testy { print $_; }
This dutifully prints each file it finds under the current working directory. However if I commend out the find command and just call that sub directly:
#!/usr/bin/perl use File::Find; #find (\&testy, "."); testy ('i am a nice parameter'); sub testy { print $_; }
it does not print 'i am a nice parameter'. This made sense to me before using File::Find since I know that subroutines have @_, not $_, even when only a single parameter is passed.

I feel like I'm missing a simple but important concept. Any input would be greatly appreciated!

Replies are listed 'Best First'.
Re: File::Find and $_ in the wanted sub
by ikegami (Pope) on Jun 04, 2010 at 20:04 UTC

    If you want something in $_, put it in $_.

    #!/usr/bin/perl testy() for 'i am a nice parameter'; sub testy { print "$_\n"; }

    I used for to assign in order to $_ to protect the previous value of $_. Clobbering your caller's $_ is a bad idea.

      So... $_ here is essentially a global variable the sub is accessing?
        yes, $_ is a global variable
        Yes, you're accessing the same $_ everywhere. So, by definition, it's a global.

        Only, it temporarily gets a new value before the call to your sub, and it gets restored to its old value afterwards.

        One way to that yourself is by using

        local $_;
        or
        local $_ = 'temporary value';
        which makes a copy of your value; or, as ikegami wrote in another reply, using for/foreach:
        foreach('temporary value') { # your code }
        which will loop exactly once, with $_ set to an alias of the value (meaning it's a different name for the same value, change the variable and the value will follow (or, for a constant, it might protest against the attempt to change a read-only value).
Re: File::Find and $_ in the wanted sub
by almut (Canon) on Jun 04, 2010 at 20:52 UTC
    I'm disturbed because I don't understand how the subroutine used as its first parameter gets $_

    The nice thing about open source is that you can take a look at the code, if you want to know how something is being done.  In many cases, an educated guess what keywords to grep for is all that's needed to jump to the right place.  In this case, when you search for $wanted_callback, you find something like this (there are several similar snippets):

    $dir= $p_dir; # $File::Find::dir $name= $dir_name; # $File::Find::name $_= ($no_chdir ? $dir_name : $dir_rel ); # $_ # prune may happen here $prune= 0; { $wanted_callback->() }; # protect against wild "next"

    As you can see, the callback routine is called without argument, but $_ (and other global variables) are populated before the call.

Re: File::Find and $_ in the wanted sub
by toolic (Bishop) on Jun 04, 2010 at 20:27 UTC
Re: File::Find and $_ in the wanted sub
by chuckbutler (Monsignor) on Jun 04, 2010 at 20:31 UTC

    Localizing $_ is an option, also:

    #!/usr/bin/perl use File::Find; #find (\&testy, "."); $_ = 'Main Line...'; testy ('i am a nice parameter'); print "$_\n"; sub testy { local $_ = shift; #Localizing it is cool, also..... print "$_\n" ; } __END__ ~Output~~ i am a nice parameter Main Line...

    Good luck. -c

    PS: The first parameter passed to a sub is in the first element of the list @_, $_[0], which is NOT the same a $_.

      I used for since for and local *_ are more thorough than local $_. One problem case:
      for ($tied) { ... local $_ = 'i am a nice parameter'; testy(); ... }

      No problem:

      for ($tied) { ... local *_; $_ = 'i am a nice parameter'; testy(); ... }

      No problem:

      for ($tied) { ... testy() for 'i am a nice parameter'; ... }
Re: File::Find and $_ in the wanted sub
by YuckFoo (Abbot) on Jun 04, 2010 at 21:17 UTC
      Thanks to you all, I get it now (I inadvertently posted anonymously).

      I'll check out File::Find::Rule, too.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://843194]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (3)
As of 2020-01-29 06:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?