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

Hi,

I have the following code
$sftp->ls($RemoteBaseDirectory . $RemoteOutgoingDirectory, sub { $Remo +teFileList[$Count++] = $_[0]->{filename} } )
I was curious is there a way to call "ls" with the "-ltr" options? Basically I want to use SFTP via Perl and pick up the oldest file each time. I've searched quite a bit on the internet with no good examples as of yet.

Thanks so much in advance!

Replies are listed 'Best First'.
Re: Perl SFTP question?
by kennethk (Abbot) on Oct 06, 2009 at 21:29 UTC
    You might do well to read How do I post a question effectively? and Writeup Formatting Tips. In particular, you should be wrapping code in <code> tags and try to make sure published code is runnable as written. You are clearly using modules but have not specified what modules you are using.

    Based upon your syntax, I am gussing you are using the Net::SFTP module. From the module's documentation:

    $sftp->ls($remote [, $subref ])

    Fetches a directory listing of $remote.

    If $subref is specified, for each entry in the directory, $subref will be called and given a reference to a hash with three keys: filename, the name of the entry in the directory listing; longname, an entry in a "long" listing like ls -l; and a, a Net::SFTP::Attributes object, which contains the file attributes of the entry (atime, mtime, permissions, etc.).

    If $subref is not specified, returns a list of directory entries, each of which is a reference to a hash as described in the previous paragraph.

    You can therefore recover the -l result by changing your key from filename to longname. Your sorting options take a little more work, since you need the complete list to sort it. I would suggest you modify your subroutine to return an array ref with the longname and mtime, and then use sort with a custom function on the returned list.

    Update: As SilasTheMonk points out below, following this approach requires a closure to cache search results rather than the simple return I describe above.

    Update 2: Having reread the above, the return value from an ordinary call to $sftp->ls contains all the information you need to recover your desired result (untested).

    my @contents = $sftp->ls($RemoteBaseDirectory . $RemoteOutgoingDirecto +ry); my @sorted = sort {$b->{a}->mtime <=> $b->{a}->mtime} @contents; print $sorted[0]->{longname};

    If the above fails, you need to look at the format of the mtime return to fix the compare.

      I thought about that approach but I rejected it. What exactly could you have the subroutine do? I think if you look at the source code, Net::SFTP will do nothing with the return value of the subroutine so your only option is to write it somewhere else. That is either going to be really bad and ugly or perhaps in some fascinating circumstances really elegant (but hard to understand).
        I naively assumed that the ls call returned a list of return results from the passed coderef, and having looked at the source I can't help wondering why the module writer didn't do that (the values just get dumped since it explicitly returns an empty array; I really don't understand that choice). I would say then the best choice is using a closure to export the data value. If the OP only wants the oldest value, a simple compare and drop would probably be best. Otherwise, he could use the closure to export an array of the mtime and longname values. He's already caching search results using a closure, so neither of those should be a challenge. Explicitly performing an element-by-element stat seems like excess. I will concede that it gains clarity.
Re: Perl SFTP question?
by SilasTheMonk (Chaplain) on Oct 06, 2009 at 21:34 UTC

    Hi goochalba,

    First of all I would read the formatting instructions for perlmonks which are listed below the message entry form. They would help make your message a lot more readable. You could even have a go at editing your message and improving its readability.

    Secondly I did have a look through the documentation of Net::SFTP and I could see nothing that quite corresponded to ls -ltr. However you should familiarise yourself with the do_opendir and do_stat methods. The code would be to loop through the directory handle, keeping a record of the oldest file and its timestamp. When the loop finishes your variable ought to hold the oldest file. As a preliminary exercise you could try implementing ls -ltr in perl. It ought to be exactly analagous.