I needed something like this the other day. I used to use a program that came with KDE - but I couldn't find it. So I whipped up the following program. Perhaps I should CPAN it - but I don't know if it is worthy of going to that length. Anyway - it should be pretty easy to setup - just change the SRC_DR, DEST_DIR, DEST_HOST, and DEST_USER variables. You will be prompted for a password. Enjoy.
#!/usr/bin/perl =head1 NAME ftp_sync.pl - Sync a directory with an ftp server =cut use strict; use warnings; use Net::FTP; use IO::Prompt qw(prompt); use File::Find qw(find); #use CGI::Ex::Dump qw(debug); sub debug { require Data::Dumper; print Data::Dumper::Dumper(@_) } ### times to run the daemon our $SRC_DIR = '/home/paul/somesite.com'; # source directory - full + path - no trailing slash our $DEST_DIR = ''; # destination directory - fu +ll path - no trailing slash our $DEST_HOST = 'somesite.com'; # remote hostname our $DEST_USER = 'someuser'; # remote username our $EXCLUDE = [ # list of files to exclude ( +that work with rsync patterns) ]; ###----------------------------------------------------------------### main(); sub main { ### setup config my $config = { src_dir => $SRC_DIR, dest_dir => $DEST_DIR, host => $DEST_HOST, user => $DEST_USER, exclude => $EXCLUDE, @ARGV, }; ### these must end with slash $config->{'dest_dir'} =~ s|/+$||; $config->{'src_dir'} =~ s|/+$||; $| = 1; my $time = time; my $pass = $config->{'pass'} || prompt("Please enter the password +for $config->{'user'}\@$config->{'host'}: ", -e => '*'); print "Connect in...\n"; my $f = Net::FTP->new($config->{'host'}, Passive => 1, Debug => 0) + || die "Couldn't ftp to $config->{'host'}: $@"; print "Logging in...\n"; $f->login($config->{'user'}, $pass) || die "Couldn't login to $con +fig->{'host'}: ".$f->message; $f->binary; my $files = {}; ### grab local file list find(sub { my $file = $File::Find::name; $file =~ s|^\Q$config->{'src_dir'}\E/*||; return if ! length($file); return if $file =~ /\bCVS\b/; my ($size, $mtime) = (stat $_)[7, 9]; $files->{$file} = { local_is_dir => (-d _ ? 1 : 0), local_size => $size, local_mtime => $mtime, }; }, $config->{'src_dir'}); #debug $files; #return; ### get remote files print "Getting files from \"$config->{'dest_dir'}\"\n"; my $get_files; $get_files = sub { my ($dir) = @_; my $old_dir = $f->pwd; $f->cwd($dir); my @files = $f->dir; foreach my $line (@files) { #drwx------ 3 ftpuser www 4096 Jun 9 2006 pe +rl5lib", #-rw------- 1 ftpuser www 4697 Dec 18 09:17 ph +oto2.html", next if $line =~ /^total\s+\d+$/; my ($perm, $i, $user, $grp, $size, $jon, $day, $yearhour, +$file) = split(/\s+/, $line, 9); next if $file =~ /^\.\.?$/; debug $line if ! $file; my $is_dir = $perm =~ /^d/ ? 1 : 0; my $full = "$dir/$file"; $full =~ s|^\Q$config->{'dest_dir'}\E||; $full =~ s|^/+||g; print "$full \r +"; my $ref = $files->{$full} ||= {}; $ref->{'remote_size'} = $size; $ref->{'remote_is_dir'} = $is_dir; if ($ref->{'local_size'} # only bother to get the mdtm if +the sizes are the same && ! $ref->{'remote_is_dir'} && $ref->{'local_size'} == $ref->{'remote_size'}) { $ref->{'remote_mtime'} = $f->mdtm($file); } if ($is_dir) { $get_files->("$dir/$file"); } } $f->cwd($old_dir); }; $get_files->($config->{'dest_dir'}); print "\n"; #debug $files; #return; ###--------------------------------------------------------------- +-### print "Syncing files...\n"; ### remove files that don't belong foreach my $full (reverse sort keys %$files) { # longest first wil +l remove files in a dir before the dir my $info = $files->{$full}; my $needs_update; my ($path, $file) = $full =~ m|^(.*?)([^/]+)$| ? ($1, $2) : do + { debug $full; die "Bad file \"$full\"" }; $path =~ s|/+$||; my $cd = $config->{'dest_dir'} .'/'. $path; if ($info->{'remote_is_dir'} && ! $info->{'local_is_dir'}) { print "Removing dir $full\n"; $f->cwd($cd) || die "Couldn't cwd to $cd: ".$f->messag +e; $f->rmdir($file) || die "Couldn't remove $full: ".$f->mess +age; } elsif (! $info->{'remote_is_dir'} && defined $info->{'remote_size'} && ! defined $info->{'local_size'}) { print "Removing file $full\n"; $f->cwd($cd) || die "Couldn't cwd to $cd: ".$f->messa +ge; $f->delete($file) || die "Couldn't delete $full: ".$f->mes +sage; } } ### add or update files that are out of date foreach my $full (sort keys %$files) { # shortest first will creat +e dirs before files my $info = $files->{$full}; my $needs_update; my ($path, $file) = $full =~ m|^(.*?)([^/]+)$| ? ($1, $2) : do + { debug $full; die "Bad file \"$full\"" }; $path =~ s|/+$||; my $cd = $config->{'dest_dir'} .'/'. $path; if ($info->{'local_is_dir'} && ! $info->{'remote_is_dir'}) { print "Creating dir $full\n"; $f->cwd($cd) || die "Couldn't cwd to $cd: ".$f->messag +e; $f->mkdir($file) || die "Couldn't mkdir $full: ".$f->messa +ge; } elsif (! $info->{'local_is_dir'}) { my $src = $config->{'src_dir'} .'/'. $full; if (defined $info->{'local_size'} && $info->{'local_size'} != ($info->{'remote_size'} || + 0)) { print "". ($info->{'remote_size'} ? "Updating" : "Crea +ting")." file $full (because of size difference)\n"; $f->cwd($cd) || die "Couldn't cwd to $cd: ".$f +->message; $f->put($src, $file) || die "Couldn't put $full: ".$f- +>message; } elsif (defined $info->{'local_mtime'} && defined $info->{'remote_mtime'} && $info->{'local_mtime'} > $info->{'remote_mtime +'}) { print "Updating file $full (because of modtime)\n"; $f->cwd($cd) || die "Couldn't cwd to $cd: ".$f +->message; $f->put($src, $file) || die "Couldn't put $full: ".$f- +>message; } } } my $elapsed = time - $time; print "Done in $elapsed seconds\n"; } ###----------------------------------------------------------------###


Sorry there isn't a little more commenting - I mainly was just using it for myself - but I figured it may help you out also.

my @a=qw(random brilliant braindead); print $a[rand(@a)];

In reply to Re: Sync via FTP by Rhandom
in thread Sync via FTP by Tanktalus

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.