perlnet-sftp

Perl reading files from SFTP server


It has been awhile since I have used perl and I am attempting to print out a list of files on a SFTP server.

This is my Perl script -

#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use autodie;

use Net::SFTP::Foreign;

# US Server Configuration
use constant {
    HOST            => "Server_Name",
    REMOTE_DIR      => "\\",
    LOCAL_DIR       => "sample/local",
    PORT            => "3235",
    USER_NAME       => "name",
    PASSWORD        => "password",
    BACKEND         => "Net_SSH2",
    DEBUG           => "0",
};

my $stfp = Net::SFTP::Foreign->new (
    HOST,
    backend         => BACKEND,
    timeout         => 240,
    user            => USER_NAME,
    password        => PASSWORD,
    port            => PORT,
    autodie         => 1,
);

#
# List remote directory contents
#
my $remotefiles;
$remotefiles = $stfp->ls(REMOTE_DIR); 

#
# Loop through remote files and print each filename
#
foreach ($remotefiles){
    my $file = $_;
    my $filename = $file->{filename};
    if($filename ne "." && $filename ne ".."){
        print"the filename is $filename";
    }
}

$stfp->disconnect;

I am getting the following error - Not a HASH reference at this line -> my $filename = $file->{filename};

Not sure what the problem is or how to fix it.


Solution

  • Here's the documentation for Net::SFTP::Foreign. This is what it says about the ls() method:

    Returns a reference to a list of entries. Every entry is a reference to a hash with three keys: filename, the name of the entry; longname, an entry in a "long" listing like ls -l; and a, a Net::SFTP::Foreign::Attributes object containing file atime, mtime,permissions and size

    So when you call this method:

    $remotefiles = $sftp->ls(REMOTE_DIR);
    

    What you get back is a reference to an array. When you try to iterate across that array:

    foreach ($remotefiles)
    

    You're not doing what you think you're doing. You're iterating over a list with a single element - which is an array reference. So $file gets an array reference, not the hash reference that you're looking for.

    So how to fix it? Well, it's simple enough. You need to dereference $remotefiles which will turn it into an array (rather than an array reference).

    # Just add a '@' to dereference the reference and
    # get to the underlying array
    foreach (@$remotefiles)
    

    Now, each time round the loop, $_ (and, therefore, $file) will contain one of the hash references described in my quote above, and everything will work as you expect.

    The important lesson to learn here is that you need to read and understand the documentation for the code that you are using. Or, at least, you need to be better at copying code from the examples. The ls() example clearly uses the dereference syntax.

    my $ls = $sftp->ls('/home/foo')
        or die "unable to retrieve directory: ".$sftp->error;
     
    print "$_->{filename}\n" for (@$ls);