http://qs321.pair.com?node_id=295673

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

Hello,

I wonder if anyone can help with a Net::FTP related question. I need to transfer an individual file from about 350 unix machines to my laptop. I have written a script to do something similar before, but in this case the filename will vary slightly each time. The format of the file is:

<hostname>shar<date>.time

For example, a file from machine with hostname ybl283 might look something like this:

ybl283shar031001.1707

The problem I am having is that the "get" function within Net::FTP (and probably ftp generally) does not accept wildcard characters (*, ? etc). "mget" accepts these characters but unfortunately this function is not part of Net::FTP. This leaves me unable to tell my script which file to transfer.

Does anyone have any suggestions, or can anybody point me in the direction of a more suitable module?

Title edit by tye

  • Comment on Net::FTP's get() does not handle wildcards

Replies are listed 'Best First'.
Re: Net::FTP
by princepawn (Parson) on Oct 01, 2003 at 16:31 UTC
    a more suitable module? why Net::FTP::Common is just what the doctor ordered :)

    Carter's compass: I know I'm on the right track when by deleting something, I'm adding functionality.

Re: Net::FTP
by RMGir (Prior) on Oct 01, 2003 at 18:00 UTC
    I like princepawn's answer.

    But just in case downloading a different module isn't an option, why not do what mget does yourself? All you need to do is grep through the results of ls to select the files to download.

    use POSIX qw(strftime); use Net::FTP; foreach my $host(@hosts) { $ftp = Net::FTP->new($host); # you probably want to use a different login $ftp->login("anonymous",'nairod@wherever.net'); # just in case... $ftp->binary(); $ftp->cwd("/whatever/place/shars/are"); my @files=grep /${host}shar\d{6}\.\d{4}/,$ftp->ls(); foreach(@files) { $ftp->get($_); } $ftp->quit(); }
    I think that might do what you want, but it's untested.
    --
    Mike
Re: ftp
by Abigail-II (Bishop) on Oct 01, 2003 at 16:32 UTC
    mget is done at the client side. It's not that hard, as FTP has methods to get a directory list (ls, dir). Get the directory listing, extract the files you want to get, and get them.

    Abigail

Re: ftp
by phydeauxarff (Priest) on Oct 01, 2003 at 16:34 UTC
    I haven't tried this but according to the doc for IO::Ftp it supports "something along the lines of mget "
    while (my $in = IO::Ftp->new('<<','//foo.bar.com/foo/bar/*.txt', TYPE= +>'a') { print "processing ",$in->filename, "\n"; #... $in->close; $in +->delete; }

    You might try giving that a shot.

Re: Net::FTP
by nimdokk (Vicar) on Oct 01, 2003 at 18:21 UTC
    If you know when the file is being generated, perhaps you could use Time::localtime (or something similar) to (re)build the filename for each host and simply do a get on that filename, perhaps storing it in a scalar variable, something like: $my_file="${hostname}shar${date}.${time}";. I'm sure there are more (and better) ways to do it, but that is one possible idea.


    "Ex libris un peut de tout"
      Dear monks, Thanks for the *very* helpful suggestions. I have decided to follow RMGir and Abigail's (duplicate node) suggestion, and grep through an ls to find the file that way. Sometimes I can't see these things and need a nudge in the right direction :) See code snippet below:

      if (@dirlist = ($ftp->ls)) { foreach $_ (@dirlist) { if (s/(\w+shar\d\d\d\d\d\d\.\d\d\d\d)/$1/) { $file = $1 if ($ftp->get($file)) { } else { print "$host: Got directory listing, but couldn't get file.\n" +; } } } }
      It could probably be written a lot simpler than that, but I like to keep things in a format I can easily understand.

      Thanks again.
        I think that there might be a problem with that. It might work, but I would suggest cleaning up one line a bit. Instead of:
        if (s/(\w+shar\d\d\d\d\d\d\.\d\d\d\d)/$1/)

        I would suggest:

        if (m/(\w+shar\d\d\d\d\d\d\.\d\d\d\d)/)
        What you are doing with s/// is substituting your regular expression for $1. The parenthesis around the expression delimit(?) $1. So it would appear that you are substituting the regular expression for itself. Then of course setting your variable $file to be equal to $1. Note the m/// in the second if statement. Also, your regular expresion could match on more than one file that fit that pattern if several files fit that scheme.


        "Ex libris un peut de tout"