我们在Perl中有autochomp吗?

Laz*_*zer 8 string perl chomp

这是我的Perl代码用于监视Unix文件夹的样子:

#!/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;
}
Run Code Online (Sandbox Code Playgroud)
  • chomp在每次任务后做一个看起来不太好.有没有办法做"autochomp"?

  • 我是Perl的新手,可能没有以最好的方式编写这段代码.欢迎任何改进代码的建议.

Gre*_*con 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;
Run Code Online (Sandbox Code Playgroud)

结果略有不同:date命令的输出包含时区,但$date上面的值不会.如果这是一个问题,请遵循Chas的优秀建议.Owens下面strftime用于获取您想要的格式.

你的分

sub touchandmail {
  `touch $cache -t "$datef"`;
  `echo "$msg" | mail -s "$subject" $owner -c $sendto`;
}
Run Code Online (Sandbox Code Playgroud)

如果出现问题,将无声地失败.沉默的失败是令人讨厌的.更好的是代码

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: $!";
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

使用system而不是反引号更能表达你的意图,因为反引号用于捕获输出.该system(LIST)表单绕过壳不必担心报价参数.

echo ... | mail ...没有shell的情况下获得shell管道的效果意味着我们必须自己做一些管道工作,但是好处 - 就像system(LIST)- 不必担心shell引用.上面的代码使用了多参数open:

对于三个或更多参数,如果MODE是'|-',则文件名被解释为输出要通过管道输出的命令,如果是'-|',则文件名被解释为管道输出给我们的命令.在双参数(和单参数)形式中,应该用'-'命令替换dash().有关此问题的更多示例,请参阅perlipc中的使用openfor IPC.

open上述叉子一个mail过程,并且$fh被连接到它的标准输入.父进程(代码仍在运行touchandmail)执行echowith 的角色print $fh $msg.close由于我们打开它的方式,调用刷新句柄的I/O缓冲区加上一点额外的:

如果文件句柄来自管道open,close则如果涉及的其他系统调用之一失败或其程序以非零状态退出,则返回false.如果唯一的问题是程序退出非零,$!则将设置为0.关闭管道也等待管道上执行的进程退出 - 如果您希望事后查看管道的输出 - 并且隐式将该命令的退出状态值放入$?${^CHILD_ERROR_NATIVE}.


jse*_*gal 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
Run Code Online (Sandbox Code Playgroud)

或更一般地说:

my $fh = io("file")->chomp->tie;
while (<$fh>) {
 # no need to chomp here !  $_ is pre-chomped
}
Run Code Online (Sandbox Code Playgroud)

当然,对于这个特殊情况,date我同意其他回答者说你可能最好使用其中一个DateTime模块,但是如果你只是阅读一个文件并希望所有的行都被chomp编辑,那么IO::All使用chomptie选项应用非常方便.

还要注意,chomp当将句柄的整个内容直接插入标量时(这就是它的实现方式),这个技巧不起作用.


Nat*_*man 5

尝试将其放入函数中:

sub autochomp {
    my $command = shift;
    my $retval = `$command`;
    chomp $retval;
    return $retval;
}
Run Code Online (Sandbox Code Playgroud)

然后为每个要执行的命令调用它,然后选择.