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

Dear Monks, I am a humble seeker of your wisdom.

I'm trying to send some information from one machine to another using ftp, in a BigBrother setting. Now, I really don't have a local file. I guess I could write the information I wan't to send to a local file, upload it and then delete the local file, but that seems unnecessary to me.

I would like to do something like:

use Net::FTP;

$ftp = Net::FTP->new("myhost", Debug => 0);
$ftp->login("user","pwd");
$ftp->cwd("/just/a/directory");
$ftp->put( <SESAME> ,"ftptest");
print SESAME "This is a test.\n";
$ftp->quit;

but that doesn't work for obvious reasons. Any suggestion what I should do? In the man-page it says that the first argument to put() can be a file handle, but how do I use it?

Kind and humble regards,
fsn

Replies are listed 'Best First'.
Re: ftp put without a local file
by wog (Curate) on Aug 31, 2001 at 18:57 UTC
    An easy way to do this would be to use IO::File's new_tmpfile to create a temporary file that will be automatically destroyed after it's closed, and possibly has no actual file on the file system. Then you can put the stuff to upload in that tempfile, rewind, and pass it to put():

    use IO::File; use Fcntl qw(:seek); my $fh = IO::File->new_tmpfile or die "Couldn't create tempfile: $!\n"; print $fh <<"END"; The contents of the file. END seek $fh, 0, SEEK_SET or die "Couldn't rewind temp file: $!\n"; $ftp->put($fh, "ftptest"); close $fh; # tempfile should be gone now.

    update: Note that $ftp->put(<SESAME>,"ftptest"); is not the right syntax to pass the SESAME file handle to $ftp->put. It will pass every line of the SESAME filehandle to it, causing failures from an unfound local file with a odd name. The correct syntax would probably be something like: $ftp->put(\*SESAME,"ftptest"); or $ftp->put(*SESAME,"ftptest");.

Re: ftp put without a local file
by suaveant (Parson) on Aug 31, 2001 at 18:56 UTC
    You need to open a file on that filehandle...
    open(SEASAME,"file_to_send" or die $!; $ftp->put( <SESAME> ,"ftptest"); close SEASAME; #or more simply $ftp->put( "file_to_send", "name_to_put_as");
    What you are doing doesn't really do much. To do what you are trying you would probably have to create a tied filehandle. For writing text to a remote file with Net::FTP look at the stor method of Net::FTP which lets you use write to put up data from a buffer.

                    - Ant
                    - Some of my best work - Fish Dinner

Re: ftp put without a local file
by Hofmator (Curate) on Aug 31, 2001 at 19:07 UTC

    Another option is using the forking open

    # Your normal code goes here if (open(SESAME, "-|")) { # parent process $ftp->put( \*SESAME ,"ftptest"); $ftp->quit; } else { # child process does all the printing print STDOUT "Whatever you like to print"; exit; }
    This should work but is untested ...

    Update: Fixed passing of filehandle as suggested by runrig.

    -- Hofmator

Re: ftp put without a local file
by MZSanford (Curate) on Aug 31, 2001 at 19:55 UTC
    You are close, but you have to print the data into the filehandle first. The following would work, were it not for the fact Net::FTP hangs while putting (not like there is alot of choice).
    ### i know this does not work, i am showing the idea my $ftp = Net::FTP->new($server,$user,$pass); $ftp->cwd("/some/dir"); pipe(R,W); $ftp->put(\*R,'filename'); print W "data here\n"; $ftp->quit;
    So, the other way is to fork a process and have it do the writting into W. Like the following (untested code ahead) :
    pipe(READ,WRITE); $pid = fork(); if ($pid == 0) { ## child (read) close(WRITE); $ftp->cwd("/some/dir"); $ftp->put(\*READ,'filename'); $ftp->quit; } else { ## parent (write) close(READ); ## ... do some cool processing for $data print WRITE $data; close(WRITE); }
    ... i have not tested this, but it should work. I guess if you are on unix you could also use mknod to make a named pipe, and use that.
    can't sleep clowns will eat me
    -- MZSanford
Re: ftp put without a local file
by runrig (Abbot) on Aug 31, 2001 at 19:50 UTC
    $ftp->put( <SESAME> ,"ftptest"); print SESAME "This is a test.\n";
    The filehandle has to be a file handle ready to read from. The $ftp->put will block until it is done reading, so you'll never get to the print that way. And you would say '\*SESAME' NOT '<SESAME>'. You might try Hofmator's suggestion (with the aforementioned fix), or try a socketpair or pipe if you don't want to tie up STDOUT.

    Another suggestion is to use an IO::Scalar handle if all the data you're sending will fit in memory.