提问人:Zilore Mumba 提问时间:10/19/2023 最后编辑:zdimZilore Mumba 更新时间:11/1/2023 访问量:106
如何在 perl 脚本中从 ftp 复制最新的
How do I copy the latest from ftp in a perl script
问:
我有一个 perl 脚本,它从 ftp 服务器上的目录中复制一个文件。文件名的格式为 FPZB01_00000118.txt。.txt 之前的数字每天递增 1。远程服务器上每天应该只有一个文件。如果有 1 个以上的文件,脚本将复制所有文件,这是不希望的。我正在尝试添加代码以仅复制今天的文件,但卡住了。 代码如下,省略了 use::strict、...和其他定义。
my $ftp = Net::FTP->new( $host, Timeout => 360, Passive => 1, Debug=>1 ) or die "Error connecting to $host: $!\n";
$ftp->binary();
$ftp->login($User,$Pass) or die "Cannot login to $User\n";
$ftp->cwd($remote_dir) or die "Could not change remote working directory to $remote_dir\n";
my @remote_files = $ftp->ls($glob);
添加代码
my @file2copy = grep /^FPZB01/, $ftp->ls();
foreach my $fl (@file2copy){
my $mdtime = $ftp->mdtm($fl);
print $f "modtime $mdtime\n";
exit;
}
结束 添加的代码
foreach my $file (@remote_files) {
# Transfer file
print "Getting $file\n" if $debug;
eval {$ftp->get($file, "$local_dir/$file") or print("Can't send file $file\n")};
if ($@ =~ /Timeout/){
print "Got a timeout Issue: $@";
}
}
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
print "copying ends\n";
exit 0;
我试图打印修改;
这是我得到的:print $f "modtime $mdtime\n"
modtime 1697627482.
不知道这意味着什么。
有关如何使用的帮助将不胜感激$ftp->mdtm($fl)
答:
只需对文件列表进行排序并传输数组中的最后一个文件即可。
# Use grep to ignore any files with the wrong name
my @remote_files = grep { /^FPZB/ } sort $ftp->ls($glob);
my $file_to_transfer = $remote_files[-1];
评论
$remote_files[-1]
这是我为使其工作而添加的内容 我有时间 12 小时前
my $TodayDate = strftime "%d.%m.%Y %H:%M:%S", localtime(time - 12*60*60);
登录后,计算我 12 小时前日期的纪元时间
my ($mday,$mon,$year,$hour,$min,$sec) = split(/[\s.:]+/, $TodayDate);
my $time = timelocal($sec,$min,$hour,$mday,$mon-1,$year);
然后,我循环浏览文件并仅查找比 12 小时前更新的文件
my @file2copy = grep /^FPZB01/, $ftp->ls();
foreach my $fl (@file2copy){
my $mdtime = $ftp->mdtm($fl);
if($mdtime > $time){
#Transfer file
其余代码保持不变,传输文件。这并不优雅,但它符合我的意愿。 在序言中添加
use strict;
use warnings;
use POSIX qw{strftime};
use Time::Local
use Time::Piece;
use Net::FTP;
use Net::SFTP::Foreign;
感谢 Ullrich 和 Toto 如何将文本日期转换为时间戳?
评论
我不确定文件选择的确切标准是什么,因为这个问题似乎与一些 OP 的评论略有不同,也许也与 OP 自己的回答略有不同。以下是一些选项。
超过 12 小时被用作 OP 答案的标准。这可以用于
my @file2copy = grep { -M < 0.5 } $ftp->ls();
由于 filetest (-X) 给出-M
-M 脚本开始时间减去文件修改时间,以天为单位。
如果需要,也可以对其进行排序(见下文)以获取最新信息。
在 OP 的评论中提到了修改时间,例如可以使用什么
use Sort::Key qw(rukeysort); # Reverse (descending) sort as Unsigned integers
my @files_latest_mtime = rukeysort { (stat $_)[9] } $ftp->ls();
当需要更复杂的排序标准时,Sort::Key 库函数非常方便,因为可以直接使用比较标准(并且在内部它使用 Schwartzian 变换以提高效率)。我使用 stat 来获取修改时间(自纪元以来的秒数);然后更大的时间用于较新的文件,因此我们需要“反向”排序(降序)。
人们还可以使用日期时间库,并从时间戳中构建 modtime 对象,然后可以随心所欲地使用。使用 DateTime
use DateTime;
use Sort::Key qw(rukeysort);
# Build an array with [filename,dt] arrayrefs, newest files first
my @files_dt_latest =
# grep if needed
rukeysort { $_->[1]->epoch }
map { [$_, DateTime->from_epoch(epoch => (stat $_)[9])] }
$ftp->ls();
say "$_->[0] => $_->[1]" for @files_dt_latest;
其中返回文件自纪元以来的年龄(以秒为单位),方便排序。或者使用哈希epoch
my %file_dt =
map { $_ => DateTime->from_epoch(epoch => (stat $_)[9])] }
$ftp->ls();
这可以根据需要进行操作
foreach my $file (rukeysort { $file_dt{$_}->epoch } keys %file_dt) {
say "$file => $file_dt{$file}" # newest first
}
或者使用库,这里 ,获取今天的日期,比如说自纪元以来的秒数,以便于与文件的时间戳进行比较。若要仅获取今天的文件,请执行以下操作:DateTime
use DateTime;
use Sort::Key qw(rukeysort);
# "today" returns today's date at 00:00:00, in UTC by default
my $today_epoch = DateTime->today(time_zone => 'local')->epoch;
my @files_today_latest_by_mtime =
rukeysort { (stat $_)[9] }
grep { (stat $_)[9] > $today_epoch }
$ftp->ls();
这也许可以针对性能(或风格?)进行优化,因为反复使用,但我怀疑人们是否能分辨出其中的区别。而“更好”的版本会更复杂。stat
评论