简体   繁体   English

我们在Perl中有autochomp吗?

[英]Do we have an autochomp in Perl?

This is what my Perl code looks like for monitoring a Unix folder : 这是我的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;
}
  • To do a chomp after every assignment does not look good. 在每次任务后做一个chomp看起来不太好。 Is there some way to do an "autochomp"? 有没有办法做“autochomp”?

  • I am new to Perl and might not have written this code in the best way. 我是Perl的新手,可能没有以最好的方式编写这段代码。 Any suggestions for improving the code are welcome. 欢迎任何改进代码的建议。

Don't use the shell, then. 那么不要使用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;

The result is slightly different: the output of the date command contains a timezone, but the value of $date above will not. 结果略有不同: date命令的输出包含一个时区,但上面$date的值不会。 If this is a problem, follow the excellent suggestion by Chas. 如果这是一个问题,请遵循Chas的优秀建议 Owens below and use strftime to get the format you want. Owens下面并使用strftime来获得你想要的格式。

Your sub 你的分

sub touchandmail {
  `touch $cache -t "$datef"`;
  `echo "$msg" | mail -s "$subject" $owner -c $sendto`;
}

will fail silently if something goes wrong. 如果出现问题,将无声地失败。 Silent failures are nasty. 沉默的失败是令人讨厌的。 Better would be code along the lines of 更好的是代码

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: $!";
    }
  }
}

Using system rather than backticks is more expressive of your intent because backticks are for capturing output. 使用system而不是反引号更能表达你的意图,因为反引号用于捕获输出。 The system(LIST) form bypasses the shell and having to worry about quoting arguments. system(LIST)形式绕过shell并且不得不担心引用参数。

Getting the effect of the shell pipeline echo ... | mail ... 获得shell管道echo ... | mail ...的效果echo ... | mail ... echo ... | mail ... without the shell means we have to do a bit of the plumbing work ourselves, but the benefit—as with system(LIST) —is not having to worry about shell quoting. echo ... | mail ...没有shell意味着我们必须自己做一些管道工作,但是system(LIST)的好处 - 不必担心shell引用。 The code above uses many-argument open : 上面的代码使用了多参数open

For three or more arguments if MODE is '|-' , the filename is interpreted as a command to which output is to be piped, and if MODE is '-|' 对于三个或更多参数,如果MODE为'|-' ,则文件名被解释为输出要输出的命令,如果MODE为'-|' , the filename is interpreted as a command that pipes output to us. ,文件名被解释为管道输出给我们的命令。 In the two-argument (and one-argument) form, one should replace dash ( '-' ) with the command. 在双参数(和单参数)形式中,应该用命令替换破折号( '-' )。 See Using open for IPC in perlipc for more examples of this. 有关此问题的更多示例,请参阅在perlipc中使用open for IPC

The open above forks a mail process, and $fh is connected to its standard input. 上面的open了一个mail进程, $fh连接到它的标准输入。 The parent process (the code still running touchandmail ) performs the role of echo with print $fh $msg . 父进程(仍然运行touchandmail的代码)使用print $fh $msg执行echo的角色。 Calling close flushes the handle's I/O buffers plus a little extra because of how we opened it: 由于我们打开它的方式,调用close刷新句柄的I / O缓冲区以及一些额外的内容:

If the filehandle came from a piped open , close returns false if one of the other syscalls involved fails or if its program exits with non-zero status. 如果文件句柄来自管道open ,则如果其中一个其他系统调用失败或者其程序以非零状态退出,则close返回false。 If the only problem was that the program exited non-zero, $! 如果唯一的问题是程序退出非零, $! will be set to 0. Closing a pipe also waits for the process executing on the pipe to exit—in case you wish to look at the output of the pipe afterwards—and implicitly puts the exit status value of that command into $? 将被设置为0.关闭管道还等待管道上执行的进程退出 - 如果您希望之后查看管道的输出 - 并隐式将该命令的退出状态值放入$? and ${^CHILD_ERROR_NATIVE} . ${^CHILD_ERROR_NATIVE}

More generally, the IO::All module does indeed provide the equivalent of an autochomp: 更一般地说, 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

or more generally: 或更一般地说:

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

Granted, for this particular case of date I would agree with the other answerers that you are probably better off using one of the DateTime modules, but if you are simply reading in a file and want all your lines to be chomp ed, then IO::All with the chomp and tie options applied is very convenient. 当然,对于这个date特殊情况,我同意其他的回答者说你最好使用其中一个DateTime模块,但是如果你只是在一个文件中读取并想要所有的行被chomp ,那么IO::All应用的chomptie选项都非常方便。

Note also that the chomp trick doesn't work when slurping the entire contents of the handle into a scalar directly (that's just the way it is implemented). 另请注意,当将句柄的整个内容直接插入标量时(这就是它的实现方式), chomp技巧不起作用。

Try putting it into a function: 尝试将其放入函数中:

sub autochomp {
    my $command = shift;
    my $retval = `$command`;
    chomp $retval;
    return $retval;
}

And then call that for each command you want to execute and then chomp. 然后为每个要执行的命令调用它,然后选择。

Use DateTime or other of the date modules on CPAN instead of the date utility. 在CPAN上使用DateTime或其他日期模块而不是日期实用程序。

For example: 例如:

use DateTime;

my $dt = DateTime->now;
print $dt->strftime('%Y%m%d%H%M.%S');

It is possible to assign and chomp in a single line using the following syntax: 它可以分配和chomp在使用以下语法一行:

chomp ( my $date = `date` );

As for speaking more Perlishly, if you find yourself repeating the same thing over and over again, roll it into a sub: 至于说更多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` );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM