这就是我的monitoring a Unix folder的Perl代码:
#!/usr/bin/perl
use strict;
use warnings;
use File::Spec::Functions;
my $date = `date`; chomp $date;
my $datef = `date +%Y%m%d%H%M.%S`; chomp $datef;
my $pwd = `pwd`; chomp $pwd;
my $cache = catfile($pwd, "cache");
my $monitor = catfile($pwd, "monme");
my $subject = '...';
my $msg = "...";
my $sendto = '...';
my $owner = '...';
sub touchandmail {
`touch $cache -t "$datef"`;
`echo "$msg" | mail -s "$subject" $owner -c $sendto`;
}
while(1) {
$date = `date`; chomp $date;
$datef = `date +%Y%m%d%H%M.%S`; chomp $datef;
if (! -e "$cache") {
touchandmail();
} elsif ("`find $monitor -newer $cache`" ne "") {
touchandmail();
}
sleep 300;
}
在每次作业后都要做chomp
看起来不太好。有没有办法做“autochomp”?
我是Perl的新手,可能没有以最佳方式编写此代码。欢迎任何改进代码的建议。
答案 0 :(得分:14)
不要使用shell。
#! /usr/bin/perl
use warnings;
use strict;
use Cwd;
use POSIX qw/ strftime /;
my $date = localtime;
my $datef = strftime "%Y%m%d%H%M.%S", localtime;
my $pwd = getcwd;
结果略有不同:date
命令的输出包含时区,但上面的$date
值不会。如果这是一个问题,请按照下面的Chas. Owens提出的优秀建议,并使用strftime
获取您想要的格式。
你的潜艇
sub touchandmail {
`touch $cache -t "$datef"`;
`echo "$msg" | mail -s "$subject" $owner -c $sendto`;
}
如果出现问题,将无声地失败。沉默的失败是令人讨厌的。更好的是
的代码sub touchandmail {
system("touch", "-t", $datef, $cache) == 0
or die "$0: touch exited " . ($? >> 8);
open my $fh, "|-", "mail", "-s", $subject, $owner, "-c", $sendto
or die "$0: could not start mail: $!";
print $fh $msg
or warn "$0: print: $!";
unless (close $fh) {
if ($! == 0) {
die "$0: mail exited " . ($? >> 8);
}
else {
die "$0: close: $!";
}
}
}
使用system
而非反引号更能表达您的意图,因为反引号用于捕获输出。 system(LIST)
形式绕过shell并且不必担心引用参数。
获得没有shell的shell管道echo ... | mail ...
的效果意味着我们必须自己做一些管道工作,但与system(LIST)
一样的好处 - 不必担心shell引用。上面的代码使用了多参数open
:
对于三个或更多个参数,如果MODE为
'|-'
,则文件名被解释为输出要通过管道输出的命令,如果MODE为'-|'
,则文件名被解释为命令管道输出给我们。在双参数(和单参数)形式中,应该用命令替换破折号('-'
)。有关此问题的更多示例,请参阅Usingopen
for IPC in perlipc。
上面open
分叉mail
进程,$fh
连接到其标准输入。父进程(代码仍在运行touchandmail
)执行echo
print $fh $msg
的角色。调用close
会刷新句柄的I / O缓冲区加上一些额外的因为我们打开它的方式:
如果文件句柄来自管道
open
,则close
如果涉及的其他系统调用之一失败或其程序以非零状态退出,则返回false。如果唯一的问题是程序退出非零,$!
将被设置为0.关闭管道也等待管道上执行的进程退出 - 如果你想查看输出管道之后 - 并隐式将该命令的退出状态值放入$?
和${^CHILD_ERROR_NATIVE}
。
答案 1 :(得分:6)
更一般地说,IO::All
模块确实提供了等效的autochomp:
use IO::All;
# for getting command output:
my @date = io("date|")->chomp->slurp;
#$date[0] contains the chomped first line of the output
或更一般地说:
my $fh = io("file")->chomp->tie;
while (<$fh>) {
# no need to chomp here ! $_ is pre-chomped
}
当然,对于date
的这种特殊情况,我同意其他的回答者,你可能最好使用其中一个DateTime模块,但如果你只是在阅读一个文件并想要你所有的行被chomp
编辑,然后应用IO::All
和chomp
选项的tie
非常方便。
另请注意,当将句柄的整个内容直接拖放到标量中时,chomp
技巧不起作用(这就是它的实现方式)。
答案 2 :(得分:5)
尝试将其放入函数中:
sub autochomp {
my $command = shift;
my $retval = `$command`;
chomp $retval;
return $retval;
}
然后为您要执行的每个命令调用它,然后选择。
答案 3 :(得分:4)
在CPAN上使用DateTime或其他日期模块而不是日期实用程序。
例如:
use DateTime;
my $dt = DateTime->now;
print $dt->strftime('%Y%m%d%H%M.%S');
答案 4 :(得分:2)
可以使用以下语法在单行中分配和chomp
:
chomp ( my $date = `date` );
至于说更多Perlishly,如果你发现自己一遍又一遍地重复同样的事情,把它滚到子:
sub assign_and_chomp {
my @result;
foreach my $cmd (@_) {
chomp ( my $chomped = $cmd );
push @result, $chomped;
}
return @result;
}
my ( $date , $datef , $pwd )
= assign_and_chomp ( `date` , `date +%Y%m%d%H%M.%S` , `pwd` );